I could not get c function calls to work inside of nasm so i wrote my own read integer procedure. Im sure its inefficient and could be greatly imporved but right now I'm interested in where the negative sign went. Any help is greatly apreiciated.

;---------------------------------------------------------;
;reads a 64 bit integer from the consol and returns in rax;
;---------------------------------------------------------;
read_int:
    push rbx    ;these registers are nonvolitile and must be saved
    push rdi
    push rsi

    mov rsi, sint   ;load string address
    mov rdi, rsi    ;duplicat address
    add rdi, 21 ;shift to end of string
    .purge:     ;sets all string contents to null
    mov byte[rsi], 0;set byte to 0
    inc rsi     ;move to next byte
    cmp rsi, rdi    ;check if at end of string
    je .end_purge   ;exit loop if at end
    jmp .purge  ;loop

    .end_purge:

    mov rax, 3  ;system call code for read_string
    mov rbx, 0  ;where to read from.  in this case std_in
    mov rcx, sint   ;where the place the resultant string
    mov rdx, 21 ;how many characters to read
    int 0x80    ;system call

    mov rcx, 0  ;set registers rax, rbx, and rcx to 0
    mov rax, 0
    mov rbx, 0

    mov rsi, sint       ;load address of string into rsi and rdi
    mov rdi, sint
    add rdi, 21     ;shift rdi to the end of the string
    mov bl, byte[rsi]   ;load the first character in the string

    cmp rbx, 43 ;if charachter is + sign continue
    je .convert
    cmp rbx, 45 ;if character is - sign continue
    je .convert 

    sub rbx, 48 ;shift character to its literal value
    cmp rbx, 0  ;test if it is a number greator than 0
    jl .endr1   ;if not exit procedure
    cmp rbx, 9  ;test if it is a number less than 9
    jg .endr1   ;if not exit procedure
    add rax, rbx    ;if it is a valid number add it to the result.
    dec rdi     ;if first char is an integer we can only read 18 more
                ;so we need to shif rdi closer to start of string
                ;this way it will exit once we have read 19 total numbers

    ;does the actual conversion from string to number
    .convert:
        inc rsi         ;increment rsi to point to next byte

        cmp rsi, rdi        ;check if we are at the end of the string
        je .endr1

        mov bl, byte[rsi]   ;load next byte
        sub rbx, 48

        cmp rbx, 0      ;if this is not a valid number end procedure
        jl .endr1
        cmp rbx, 9      
        jg .endr1       

        mov rdx, 10
        mul rdx         ;multiply rax by 10 to make room for new ones place
        add rax, rbx        ;add the new number to the result
    jmp .convert

    .endr1:
    mov bl, byte[sint]  ;get first byte of integer string if minus do -result
    cmp rbx, 45
    jne .endr2

    not rax     ;convert rax to a negative
    inc rax     ;increment to get back to origional magnitude


.endr2:
pop rsi     ;restore saved values
pop rdi
pop rbx
ret         ;return to caller

;-----------------------------------------;
;prints the integer in rax to standard out;
;-----------------------------------------;
print_int:
    push rbx    ;save these registers as they are nonvolitile
    push rdi
    push rsi

    mov rsi, sint   ;load address to store string
    mov r10, 10 ;load divisor
    mov rcx, 0  ;clear registers
    mov rdx, 0

    mov rdi, rsi    ;copy address
    add rdi, 21 ;shift to end of space
    .purge:     ;make all bytes null same as above
    mov byte[rsi], 0
    inc rsi
    cmp rsi, rdi
    je .end_purge
    jmp .purge

    .end_purge:
    mov rsi, sint   ;restore origional values
    mov rdi, 0

    cmp rax, 0  ;compair the number to 0 
    jg .convert ;if its positive skip to convert
    jl .neg     ;if its negative skip to neg

    mov byte[rsi], 48   ;if its 0 add literal 0 to string
    jmp .endp1      ;jump to print
    .neg:

    not rax     ;take negation to make positive
    inc rax     ;increment to restore magnitude

    mov byte[rsi], 45   ;add the - sign to print string
    inc rsi         ;increment pointer

    .convert:
        cmp rax, 0  ;see if we are out of integers to convert
        je .converts    ;if so create string with chars
        inc rcx     ;increment counter

        div r10     ;divide by 10 placeing remainder in rdx and quotient in rax
        add rdx, 48 ;convert remainder to its char value

        mov r8,  rdx    ;move to r8
        push r8     ;push onto the stack
        mov rdx, 0  ;set rdx to 0

    jmp .convert    ;loop
    .converts:
        cmp rcx, 0  ;see if we are out of characters to concat
        je .endp1   ;if so go to print
        dec rcx     ;decrement counter

        pop rbx         ;pop a char
        mov byte[rsi], bl   ;concat char to string
        inc rsi         ;adjust string pointer to next empty slot

    jmp .converts   ;loop


    .endp1:
    mov rax, 4  ;system call code for print_string
    mov rbx, 1  ;print to std_out
    mov rcx, sint   ;address of string to print
    mov rdx, 20 ;number of chars to print
    int 0x80    ;system call

    pop rsi     ;restore saved values
    pop rdi
    pop rbx
ret

I also included my print procedure to make it easier to test the read procedure should you decide to run it.

Thanks.

Recommended Answers

All 5 Replies

I've read through your code a few times, and nothing's standing out to me yet. One technique that tends to help me is to take the code off-screen, get a pen and paper, then make a flowchart of what the code has to do, then write bits of the code over again. This tends to eliminate silly human errors that were made the first time around.
In the mean time, I'll read your code more closely.

I could not find anything wrong with it but I have pretty limited knowledge of x86, I started studyning it about 12 hours before I posted this. Ill make another try at rewriting it later though thanks for the help.

Another reason bugs can arise is that code gets a bit untidy and hard to follow. For your benifit, I'd suggest looking up about the rep, lodsb, stosb and loop instructions. You'll probably find these quite useful

Using rep and stosb in your purge functions can simplify and condense it down to:

    mov rdi, sint   ; destination index = string
    mov rcx, 21     ; we're going to repeat 21 times
    xor al, al      ; zero-out al
    rep stosb       ; Repeat stosb RCX (21) times

So the next thing I'd do is go through my code and try to condense it into as little as possible, so that when you're trying to debug, it's a lot easier.

I started studyning it about 12 hours before I posted this

Wow, that's quite good progress!

Are there any other opcodes/prefixes you find particularly useful?

Also id like to make sure i understand how these 4 work:
rep -simply repeate the following instruction rcx number of times.
lodsb, lodsw, lodsd -load byte/word/ect. at address rsi and increment rsi by 1,2,4 respectively?
stosb, stosw, stosd -store byte/word/ect/ at address rdi and increment rdi by 1,2,4 respectively?
loop -loop rcx number of by jumping to address specified after opcode?

Unfortunately due to time constraints I have to take a couple day break from asm and hope to continue this conversation when I get back.

Thanks for the help.

It depends on what you're doing as to which size (*sb, *sw, *sd, etc) you use.
And yes, those are all correct.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.