Author Topic: Help for a newbie.  (Read 6903 times)

Offline RogerRabbit

  • New Member
  • Posts: 1
Help for a newbie.
« on: May 07, 2011, 07:20:49 AM »
Hi there, I'm using YASM (which I understand to be very similar to NASM) and I was wondering if you could help me. I'm trying to write a bit of code to use bubblesort to sort a 10 character string. Here's what I've got:
Code: [Select]
arrSize equ 10

section .bss ; unititialised data

iobuf   resb      1 ; used by putChar
strbuf  resb    arrSize

section .data ; initialized data and constants

msg db 'Enter 10 Digits: '
len equ $ - msg
msg1 db 'Sorted: '
len1 equ $ - msg1

section .text ; instructions

        global _start
_start:

mov edx, len
mov ecx, msg
call putString ;print message

mov esi, '0' ;pointer
mov edi, strbuf ;base add of array

reading:
        call getChar

mov [edi+1*esi], al ; store it
 
inc esi
cmp esi, arrSize
        jl reading

mov al, 0x0A ; newline
call putChar

mov edx, len1
mov ecx, msg1
call putString

mov esi, '0' ; index = 0
mov edi, [arrSize] ; index = 0

sorting: ;edi is sorting loop index

innerLoop:
swap:
mov eax, [edi+1*esi]
cmp eax, [edi+2*esi]
jl swapend
mov eax, [edi+1*esi]
mov ebx, [edi+2*esi]
mov [edi+1*esi], ebx
mov [edi+2*esi], eax
swapend:

cmp esi, edi
jl innerLoop;


dec edi
cmp edi, 1 ;loop
jg sorting

writing:
        mov     al, [edi+1*esi]      ; i'th byte of str
        call    putchar

        dec     esi
        cmp     esi, 0
        jge     writing

        mov     al, 0x0A             ; newline
        call    putchar


        mov     eax, 1               ; exit()
        int     0x80                 ; make the system call


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

putChar: ; write a char to stdout
mov [iobuf], al ; load iobuf with al
mov edx, 1
mov ecx, iobuf
mov ebx, 1
mov eax, 4
int 0x80
mov al, [iobuf] ; restore char in al
ret

getChar: ; read a char from stdin
rawmode
mov edx, 1
mov ecx, iobuf
mov ebx, 0
mov eax, 3
int 0x80
normalmode
mov     al, [iobuf] ; load al
ret

putString: ; ecx has address, edx has length
mov ebx, 1
mov eax, 4
int 0x80
ret

I'm running into a few issues. When I run, i get a segmentation fault as follows:
Code: [Select]
roger@assm -$  ./sort
Enter 10 Digits: 1234567890
Segmentation fault
roger@assm -$  234567890
234567890: command not found
/code]
« Last Edit: May 07, 2011, 07:30:40 AM by RogerRabbit »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Help for a newbie.
« Reply #1 on: May 07, 2011, 09:23:37 AM »
Code: [Select]
mov edi, [arrSize] ; index = 0

There's your segfault. "arrSize" = 10, so you're trying to read the contents of memory location 10 - which is outside your process's memory. Just "mov edi, arrSize", no brackets.

The "234567890" on the command line suggests that "getchar" isn't working as intended. What are "rawmode" and "normalmode"? I'll have to look at this some more...

Best,
Frank


Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Help for a newbie.
« Reply #2 on: May 08, 2011, 11:17:45 AM »
As you've probably discovered, that still segfaults...

Code: [Select]
mov esi, '0' ; index = 0
mov edi, [arrSize] ; index = 0

sorting: ;edi is sorting loop index

innerLoop:
swap:
mov eax, [edi+1*esi]
cmp eax, [edi+2*esi]
jl swapend
mov eax, [edi+1*esi]
mov ebx, [edi+2*esi]
mov [edi+1*esi], ebx
mov [edi+2*esi], eax
swapend:

cmp esi, edi
jl innerLoop;

You make esi '0' (30h or 48 decimal) and edi... well, "arrsize" maybe. [esi + edi] is still going to be outside your process' memory. You need to get "strbuf" in there somehow! Probably in one of those registers. Then, you want to load, compare, and maybe swap bytes (right?) but you're using 32-bit registers, which will load and compare dwords. You probably want to use al and bl there - or maybe al and ah, leave ebx alone? Still 32-bit registers for addressing memory, of course. When you get to the end, you compare edi with esi - you haven't changed either, so you're going to "jl" always or never. You probably don't want "2*esi" there, but [edi + esi +1] - to compare (and swap?) the "next" byte to the one you're examining. That whole section needs re-writing. (and some of the remainder, too, but most of it's pretty good)

I still don't know what "rawmode" and "normalmode" are... Well, I think I can guess what they're supposed to do... sys_read doesn't return after reading just the one character(!). It only puts one character in your buffer, but it doesn't return until you hit "enter". Remaining characters that were typed stay in the "OS's buffer" - available for the next sys_read, which will end up on the command line, if it doesn't get read within your program. If you can keep it from segfaulting, and if the pesky user enters only ten "digits", this may not be a problem. There's a way - using sys_ioctl, I think - to make a read on STDIN return "just one key, please", so you don't have to prompt "Hit any key as long as it's 'Enter' to continue"... Have you got some macros for that, or something?

Best,
Frank