NASM - The Netwide Assembler

NASM Forum => Programming with NASM => Topic started by: grvtiwari on June 03, 2012, 06:07:10 AM

Title: Help Needed
Post by: grvtiwari on June 03, 2012, 06:07:10 AM
Hi everyone.

I am just a beginner. I have huge interest in Assembly Programming. I started and now I am facing a lot of problems. I hope that my all questions would be answered here very soon. Thanks.

Code: [Select]
;Assembly Program to print a message

;30 May 2012

SECTION .data

    msg    db    'A'                        ;String to be printed
    len    equ    $-msg                        ;Length of the String
   
    msg1    db    65
    len1    equ    $-msg1
   
SECTION .bss

   

   
SECTION .code

    global _start
   
   
    _start:
       
        mov eax, 4
        mov ebx, 1
        mov ecx, msg
        mov edx, len
        int 80h
       
        mov eax, 4
        mov ebx, 1
        mov ecx, msg1
        mov edx, len1
        int 80h
       
        mov eax, 4
        mov ebx, 1
        mov ecx, 65
        mov edx, 2
        int 80h
       
        mov eax, 1
        mov ebx, 0
        int 80h

Now, according to me, output of the code should be AAA but it is AA. The last write call is not working. With little messing up, I reached to a conclusion that ecx needs an address or a pointer to what we want to be printed. With that opinion, I tried to mov [ecx], 65 but an error popped up saying that operaion size not specified. I am facing again some problems in loop or let me be more specific, I know that when we take input, it is characters not integers. How to deal with the characters, is the main problem.

Until then.
Thanks in advance.
Title: Re: Help Needed
Post by: Frank Kotler on June 03, 2012, 11:26:46 AM
You're on the right track with:
Code: [Select]
mov [ecx], 65
Nasm complains about "operation size not specified" 'cause it doesn't know whether to move a byte (8 bits), a word (16 bits), or a dword (32 bits) into the address pointed to by ecx. You gotta tell it!
Code: [Select]
mov byte [ecx], 65
That may do what you want... if ecx still points to "msg1", you'll overwrite a byte 65 with another byte 65... not too useful, but it should work. In your first two writes, you use "len" and "len1" in edx - both 1 - but on the third attempted write, you use 2 in edx. What did you have in mind there?

You might want to use something like...
Code: [Select]
...
section .bss
  unknown resb 1
section .text ; ".text" is the standard name, not ".code"
...
  mov eax, 4
  mov ebx, 1
  mov ecx, unknown
  mov byte [ecx], 65 ; now it's known!
  mov edx, 1
  int 80h
...
If you don't want to specify another variable for the "unknown" character, you could do:
Code: [Select]
...
  push 65
  mov ecx, esp ; buffer's on our stack
  mov edx, 1
  int 80h
  add esp, 4 ; clean up the stack
...
Or one I like...
Code: [Select]
...
  mov al, 65
  call putc
...
;exit!
...
;-----------------------
; prints the character in al to stdout.
; returns - all caller's regs preserved.

putc:
  push edx
  push ecx
  push ebx
  push eax ; must be pushed last - doubles as our buffer
  mov eax, 4
  mov ebx, 1
  mov ecx, esp
  mov edx, 1
  int 80h
  pop eax
  pop ebx
  pop ecx
  pop edx
  ret
;---------
That saves more of the caller's regs than is usual, and doesn't return any result - or possible error! - not very efficient, but it's convenient. :)

You'll probably want to print a linefeed (10 decimal, 0Ah) last, just for a neater display...

Best,
Frank

Title: Re: Help Needed
Post by: grvtiwari on June 03, 2012, 12:55:47 PM
First. Thanks for the prompt reply.

I got every bit of it. And seriouly,. I didnt knew that
Code: [Select]
mov [eax], 65 would overwrite the very first byte pointed by eax register. Thanks for it. I too have thoughts to back up all the registers during the system call. Its just that I had not any need for it till now. Anyway, I was actually trying to enter the count value from the user. After reading your lot of replies over other topics, now I know that we enter characters not numbers. For example, when I enter 1 plus linefeed, it gets stored as two byte, one for 49 and other for line feed. Suppose, I kept the input buffer to 1 byte only, I entered 1 which would be character (and at the same time, this makes character A(ASCII 65 another option), so I think that if I stored this 1 or A into count variable and later moved it in ECX, then my loop should work for 49 times for 1 and 65 time for A, but I am always tormented by infinite loop. Why is that happening ?
Title: Re: Help Needed
Post by: Frank Kotler on June 03, 2012, 10:39:23 PM
You don't show any loop... but I can imagine. A loop needs to have some "exit condition", or it will be an "infinite loop". The actual "loop" instruction loops ecx times, decrementing ecx each time until ecx becomes zero, at which time it falls through into whatever code follows the "loop" instruction - that's its "exit condition". If you're not using the "loop" instruction (common - "loop" is short but slow) you need to arrange some "exit condition"... or loop forever.

For example, if you were doing something with keyboard input, it would usually end with a linefeed, so you might want to do something like...
Code: [Select]
...
  mov esi, buffer
looptop:
  mov al, esi
  inc esi ; get ready for next one
  cmp al, 10
  jz loopend
; do something with the character in al
  jmp looptop
loopend:
...

Printing out our own "ASCII chart" might make an interesting exercise... although "man ascii" will do it for us. Note that ascii codes less than 32 decimal (20h) are "control codes", not real "characters" so trying to print them will just mess up the display. "True ASCII" is 7 bit code so you probably don't want to print anything over 127 decimal (7Fh)...

If you post the infinite loop that's tormenting you, we can probably help, but you can probably figure it out on your own if you think about what the "exit condition" needs to be to do what you want...

Best,
Frank

Title: Re: Help Needed
Post by: grvtiwari on June 04, 2012, 12:34:45 AM
Here is the code which is just pesking me up.

Code: [Select]


SECTION .data

    msg    db    'Enter the number',10
    len    equ    $-msg

    msg1    db    'Message',10
    len1    equ    $-msg1
   
SECTION .bss

    count    resb    1
   
SECTION .text

    global _start                ;Entry point of the Program
   
    _start:
   
        mov eax, 4
        mov ebx, 1
        mov ecx, msg
        mov edx, len
        int 80h
       
        mov eax, 3
        mov ebx, 0
        mov ecx, count
        mov edx, 1
        int 80h
       
        mov ecx, count
        call loopmsg
       
        mov eax, 1
        mov ebx, 0
        int 80h
       
    loopmsg:
   
        push ecx
       
        mov eax, 4
        mov ebx, 1
        mov ecx, msg1
        mov edx, len1
        int 80h
       
        pop ecx
        loop loopmsg
        ret


Please, I am just a beginner. And I am currently stuck on the loop. After this, with your wish, I will create program for ASCII table.
Thanks Again.
Title: Re: Help Needed
Post by: grvtiwari on June 04, 2012, 12:39:13 AM
And sir, I intentionally took edx as 1 for reading input. I do not have any idea on how to deal with two bytes in input buffer. So, I tought it would be easy for me to get 1 input only. And sir, I know if user prints 1ls -l then line feed, what will happen. Credit to you.


Thanks.
Title: Re: Help Needed
Post by: Frank Kotler on June 04, 2012, 02:52:41 AM
I think your main problem is right here:
Code: [Select]
        mov ecx, count
        call loopmsg
You're loading ecx with the address of the "count" variable. This isn't actually "infinite", but is way more than you want! You probably want "[contents]" of the "count" variable...
Code: [Select]
mov ecx, [count]
call loopmsg
But that isn't quite correct, either. For one thing, using ecx will get four bytes from "[count]", and we only wanted one. For another thing, sys_read will put a "character" (its ASCII code) in "[count]", which is not the same as the number the character represents. We can fix these issues (there are potentially more) without introducing any new instructions...
Code: [Select]
mov ecx, 0 ; xor ecx, ecx better? - just to zero upper bits
mov cl, [count]
sub cl, '0' ; or 48 or 30h - convert to number
call loopmsg

The "movzx" instruction would come in handy here...
Code: [Select]
movzx ecx, byte [count]
would "zero extend" the byte into all of ecx, making sure that the upper bits are zero which is what we want. (The "movsx" varient "sign extends" a byte - or word - into a 32 bit register. If you don't yet "get" how we represent negative numbers... don't worry about it) Note that Nasm knows how big ecx or cl are, so we don't need to specify a size, but in this case we do.

This ASSumes a "well behaved" user who will enter just one character which is a decimal digit, but within those limits should do what you want. You'll find that dealing with erroneous or unexpected input takes much more code than just doing the "work" we're interested in... but we "should" do it! We can get to that...

(my name's "Frank" - "Sir" was my grandfather. :) )

Best,
Frank

Title: Re: Help Needed
Post by: grvtiwari on June 04, 2012, 07:52:06 AM
Hi again. I know my questions are more than easy for you. But believe, I nearly want to bang my head against wall but I want to learn thats why I am still here. I will be here.
Anyway, your last reply provided me a bit of confusion.
Code: [Select]
mov esi, buffer
looptop:
  mov al, esi
  inc esi ; get ready for next one
  cmp al, 10
  jz loopend
; do something with the character in al
  jmp looptop
loopend:

Why we aren't comparing for [al] to be 10. I mean that al should contain an address to a location that holds 10. Isn't ?

Suppose user entered 8000 plus linefeed. I pointed esi to the location and then changed this '8000' (which is 4 byte, isn't ?), to 8000 (I think would be able to be stuffed inside a byte, so 1 byte), obviously this 8000 would now be in a register. But I cant use it to print. I need an address. So, the currect operaion must be
Code: [Select]
mov byte[ecx], eax     ; If eax contains 8000
or

Code: [Select]
mov byte[ecx], 8000
for displaying it on the stdout.

And one more thing, to display 12 or 22 anything with more than 1 digit, do I need more than 1 byte ? I mean if I store 65 in a variable and then mov ecx, var it would print A. So, I think it would be needed to changed to more than 1 byte. 1 for '6' and other for '5' ?

Title: Re: Help Needed
Post by: grvtiwari on June 04, 2012, 12:27:10 PM
With all I learned till now, I tried to create to input like 12 plus linefeed. Convert it to number 12, since I do not know a way to print 12, so I tried to print a msg 12 times, but it is not working. What is it I am doing wrong ?
Code: [Select]
;Assembly Program to accept input and turn it into real integer..
;
;4 June 2012

SECTION .data

    msg    db    'Enter the number: ',10        ;Input String
    len    equ    $-msg                ;Length of the String
   
SECTION .bss

    input    resb    10                ;Input Reserved Buffer
   
SECTION    .text
   
    global _start
   
    _start:
   
        mov ecx, msg                ;Moving the string address to be printed
        mov edx, len                ;Setting up the output length
        call print                ;Calling the read procedure
       
        mov ecx, input                ;Moving the input address
        mov edx, 10                ;Setting up the Input Buffer Space
        call read                ;Calling the read procedure
       
        mov esi, input                ;Source Index to the Input
        mov eax, 10
        mov ecx, 0
        call jump
       
    jump:
   
        mov ebx, [esi]                ;Stroing the content in here
        inc esi                    ;Pointing to the next
        cmp ebx, 10                ;Compare for new line
        jz jumpend                ;if zero flag is set, jump to jumpend procedire
       
        sub ebx, '0'                ;Changed it to integer
        mul ecx                    ;multiply by 10
        add ecx, ebx                ;Adding ecx and ebx
        call jump                ;Calling the jump procedure
       
    jumpend:
       
        push ecx                ;Since ECX contains final conversion, save it
       
        mov ecx, msg                ;Setting up the Msg to be printed
        mov edx, len                ;Setting up the len
        call print                ;calling print
       
        pop ecx                    ;Popping the value of ECX
       
        loop jumpend                ;Runnning a loop to check that we converted sucessfully
       
        call exit                ;Calling the Exit Procedure
       
    print:
       
        mov eax, 4                ;Setting up the write system call
        mov ebx, 1                ;Setting up the stdout
        int 80h                    ;Kernel ! You Do it.
        ret                    ;Return to callee
       
    read:
       
        mov eax, 3                ;Setting up the Read system call
        mov ebx, 0                ;Setting up the stdin
        int 80h                    ;Kernel ! You Do it.
        ret                    ;Return to callee   
       
    exit:
   
        mov eax, 1                ;Settiing up the Exit system call
        mov ebx, 0                ;Setting up the return status
        int 80h                    ;Kernel ! You Do it.
Title: Re: Help Needed
Post by: Frank Kotler on June 04, 2012, 02:02:43 PM
Well, it doesn't help that I blew the example! I meant [esi]! (although your questions are "easy", I'm still capable of making a mistake!)
Code: [Select]
; address of buffer into esi
 mov esi, buffer
looptop:
; get one character/byte into al
  mov al, [esi] ; <- error in previous code!
  inc esi ; get ready for next one

; see if it's the expected end of input
  cmp al, 10
; if so, we're all done
  jz loopend
; do something with the character in al
  jmp looptop
loopend:

So al isn't an address - an address takes 32 bits (or 16 bits in old dos code, or 64 bits in 64-bit code), but a single byte/character from our buffer...

Quote
Suppose user entered 8000 plus linefeed. I pointed esi to the location and then changed this '8000' (which is 4 byte, isn't ?),

Right... but with the linefeed, 5. But you probably want a bigger buffer than that - a 32-bit number could need 10 digits... plus 1 for the linefeed... maybe a leading '+' or '-'? We're not dealing with zero-terminated strings here, but don't forget to leave a byte for it if you need it...
Code: [Select]
count resb 16
... ought to be plenty. Won't hurt to make the buffer too big...

Quote
to 8000 (I think would be able to be stuffed inside a byte, so 1 byte), obviously this 8000 would now be in a register.

Yes, but the number 8000 won't fit in a byte (only up to 255 in a byte).  It would fit in a word, in this case, but might as well use a full 32-bit register - there's no advantage to using 16-bit registers in 32-bit code.

Quote
But I cant use it to print. I need an address.

Right, and worse... to print it you need to convert the number 8000 back into '8', '0', '0', '0'... But I thought we were going to use this number the user entered as a count to repeat "message"? We could print it too, I suppose...

It seems to me that you might be "stuck" on the "convert the 4 characters '8000' to the number 8000" part. Or maybe you've got that? I fear I confused you by typoing the example. Where are we?

Best,
Frank

Ah, new post! Lemme see...
Code: [Select]
;Assembly Program to accept input and turn it into real integer..
;
;4 June 2012

SECTION .data

    msg    db    'Enter the number: ',10        ;Input String
    len    equ    $-msg                ;Length of the String
   
SECTION .bss

    input    resb    10                ;Input Reserved Buffer
   
SECTION    .text
   
    global _start
   
    _start:
   
        mov ecx, msg                ;Moving the string address to be printed
        mov edx, len                ;Setting up the output length
        call print                ;Calling the read procedure
       
        mov ecx, input                ;Moving the input address
        mov edx, 10                ;Setting up the Input Buffer Space
        call read                ;Calling the read procedure
       
        mov esi, input                ;Source Index to the Input
        mov eax, 10
        mov ecx, 0
        call jump
       
    jump:
   
        mov ebx, [esi]                ;Stroing the content in here

At this point, you've put 4 bytes into ebx, but we really only want one at a time... but we eventually want it in a 32-bit register. How about an "and" to zero out the high bits and leave just a byte untouched?
Code: [Select]
  and ebx, 0FFh
        inc esi                    ;Pointing to the next
        cmp ebx, 10                ;Compare for new line
        jz jumpend                ;if zero flag is set, jump to jumpend procedire
       
        sub ebx, '0'                ;Changed it to integer
        mul ecx                    ;multiply by 10
        add ecx, ebx                ;Adding ecx and ebx
        call jump                ;Calling the jump procedure

Do you really want to "call" jump here? I would think "jmp jump"...

Code: [Select]
    jumpend:
       
        push ecx                ;Since ECX contains final conversion, save it
       
        mov ecx, msg                ;Setting up the Msg to be printed
        mov edx, len                ;Setting up the len
        call print                ;calling print
       
        pop ecx                    ;Popping the value of ECX
       
        loop jumpend                ;Runnning a loop to check that we converted sucessfully
       
        call exit                ;Calling the Exit Procedure
       
    print:
       
        mov eax, 4                ;Setting up the write system call
        mov ebx, 1                ;Setting up the stdout
        int 80h                    ;Kernel ! You Do it.
        ret                    ;Return to callee
       
    read:
       
        mov eax, 3                ;Setting up the Read system call
        mov ebx, 0                ;Setting up the stdin
        int 80h                    ;Kernel ! You Do it.
        ret                    ;Return to callee   
       
    exit:
   
        mov eax, 1                ;Settiing up the Exit system call
        mov ebx, 0                ;Setting up the return status
        int 80h                    ;Kernel ! You Do it.

Well... I think I need a nap. I'll be back! :)

Best,
Frank

Title: Re: Help Needed
Post by: grvtiwari on June 04, 2012, 08:22:12 PM
Yes. I did it. I misread the instruction for mul command. nxn gives 2n bits. If we use 32 bit reg multiplication, so, upper 32 bit get in edx and lower in eax, so in short after multiplying, I was losing eax.

Here is the code.

Code: [Select]
;Assembly Program to accept input and turn it into real integer..
;Arc-PC
;4 June 2012

SECTION .data

    msg    db    'Enter the number: ',10        ;Input String
    len    equ    $-msg                ;Length of the String
   
    msg1    db    'Goodluck for ASM :) .', 10    ;String2
    len1    equ    $-msg1                ;Length of my msg
   
SECTION .bss

    input    resb    10                ;Input Reserved Buffer
   
SECTION    .text
   
    global _start
   
    _start:
   
        mov ecx, msg                ;Moving the string address to be printed
        mov edx, len                ;Setting up the output length
        call print                ;Calling the read procedure
       
        mov ecx, input                ;Moving the input address
        mov edx, 10                ;Setting up the Input Buffer Space
        call read                ;Calling the read procedure
       
        mov esi, input                ;Source Index to the Input
        mov eax, 10
        mov ecx, 0
        call jump
       
    jump:
   
        mov ebx, [esi]                ;Stroing the content in here
        and ebx, 00FFh
        inc esi                    ;Pointing to the next
        cmp ebx, 10                ;Compare for new line
        jz jumpend                ;if zero flag is set, jump to jumpend procedire
       
        sub ebx, '0'                ;Changed it to integer
        mul ecx                    ;Its 32x32, so lower 32 in eax and upper 32 in edx
        mov ecx, eax                ;Moving the lower 32 bit in ecx
        mov eax, 10                ;Setting eax to 10 again
       
        add ecx, ebx                ;Adding ecx and ebx
        jmp jump                ;Calling the jump procedure
       
    jumpend:
       
        push ecx                ;Since ECX contains final conversion, save it
       
        mov ecx, msg1                ;Setting up the Msg to be printed
        mov edx, len1                ;Setting up the len
        call print                ;calling print
       
        pop ecx                    ;Popping the value of ECX
       
        loop jumpend                ;Runnning a loop to check that we converted sucessfully
       
        call exit                ;Calling the Exit Procedure
       
    print:
       
        mov eax, 4                ;Setting up the write system call
        mov ebx, 1                ;Setting up the stdout
        int 80h                    ;Kernel ! You Do it.
        ret                    ;Return to callee
       
    read:
       
        mov eax, 3                ;Setting up the Read system call
        mov ebx, 0                ;Setting up the stdin
        int 80h                    ;Kernel ! You Do it.
        ret                    ;Return to callee   
       
    exit:
   
        mov eax, 1                ;Settiing up the Exit system call
        mov ebx, 0                ;Setting up the return status
        int 80h                    ;Kernel ! You Do it.


I was trying to put 10 as '1' and '0'. I have an idea. Suppose we have count in ecx. Check for ecx >10, if yes, ecx /10 and store the mod somewhere, then change that mod to char. But I do not know what to do after it. I mean how store it for printing. Another issue is numbers would be in reverse order.

A hint please...

Thanks..
Title: Re: Help Needed
Post by: Frank Kotler on June 05, 2012, 05:07:43 AM
That seems to work great. I still think you've got a "call" in there where you don't need it - "call jump" could just fall through, and I moved "exit" up to where it could fall through. Since they aren't really subroutines - we don't "ret" from them - we shouldn't really "call" them. Worked okay the way you had it...

I added a "number_to_string" routine. As you observe, we get the digits in the wrong order, so we push 'em on the stack, counting each one. Then, when eax gets down to zero after the "div", we're done, so pop 'em back off the stack and store 'em in a buffer to print. There are other ways to do this, but this is "easy"(?) to understand...

Code: [Select]
;Assembly Program to accept input and turn it into real integer..
;Arc-PC
;4 June 2012

SECTION .data

    msg    db    'Enter the number: ',10        ;Input String
    len    equ    $-msg                ;Length of the String
   
    msg1    db    'Goodluck for ASM :) .', 10    ;String2
    len1    equ    $-msg1                ;Length of my msg
   
SECTION .bss

    input    resb    10                ;Input Reserved Buffer
    ascbuf resb 12 ; buffer for string
    count resd 1
   
   
SECTION    .text
   
    global _start
   
    _start:
   
        mov ecx, msg                ;Moving the string address to be printed
        mov edx, len                ;Setting up the output length
        call print                ;Calling the read procedure
       
        mov ecx, input                ;Moving the input address
        mov edx, 10                ;Setting up the Input Buffer Space
        call read                ;Calling the read procedure
       
        mov esi, input                ;Source Index to the Input
        mov eax, 10
        mov ecx, 0
;        call jump
       
    jump:
   
        mov ebx, [esi]                ;Stroing the content in here
        and ebx, 00FFh
        inc esi                    ;Pointing to the next
        cmp ebx, 10                ;Compare for new line
        jz jumpend1                ;if zero flag is set, jump to jumpend procedire
       
        sub ebx, '0'                ;Changed it to integer
        mul ecx                    ;Its 32x32, so lower 32 in eax and upper 32 in edx
        mov ecx, eax                ;Moving the lower 32 bit in ecx
        mov eax, 10                ;Setting eax to 10 again
       
        add ecx, ebx                ;Adding ecx and ebx
        jmp jump                ;Calling the jump procedure

    jumpend1:
mov [count], ecx
       
    jumpend:
        push ecx                ;Since ECX contains final conversion, save it

       
        mov ecx, msg1                ;Setting up the Msg to be printed
        mov edx, len1                ;Setting up the len
        call print                ;calling print
       
        pop ecx                    ;Popping the value of ECX
       
        loop jumpend                ;Runnning a loop to check that we converted sucessfully

mov eax, [count]
mov edi, ascbuf
call number_to_string

mov ecx, ascbuf ; buffer
mov edx, eax ; length returned from number_to_string
call print

;        call exit                ;Calling the Exit Procedure
    exit:
   
        mov eax, 1                ;Settiing up the Exit system call
        mov ebx, 0                ;Setting up the return status
        int 80h                    ;Kernel ! You Do it.

; subroutines       
    print:
       
        mov eax, 4                ;Setting up the write system call
        mov ebx, 1                ;Setting up the stdout
        int 80h                    ;Kernel ! You Do it.
        ret                    ;Return to caller
       
    read:
       
        mov eax, 3                ;Setting up the Read system call
        mov ebx, 0                ;Setting up the stdin
        int 80h                    ;Kernel ! You Do it.
        ret                    ;Return to callee   
       
;------------------
; call with eax = number
; edi = buffer to put string
; returns eax = length of string
    number_to_string:
xor ecx, ecx
mov ebx, 10
    .top:
xor edx, edx
div ebx
add edx, '0'
push edx
inc ecx
test eax, eax
jnz .top
mov edx, ecx
    .poploop:
pop eax
stosb
loop .poploop
mov eax, edx
ret
;--------------------

I had to rearrange a couple of things to make it work, but I think you'll still recognize it. Would look better with another linefeed at the end... maybe should have saved some of the registers the "number_to_string" routine trashes... could be better, but it prints the number...

Best,
Frank

Title: Re: Help Needed
Post by: grvtiwari on June 07, 2012, 06:58:04 PM
I am trying to make my own program for converting number to string. Lets share my progress.
Code: [Select]
;Program to convert number to string
;Arc-PC
;7 June 2012

SECTION .data

    msg    db    'hey! I am there always', 10
    len     equ    $-msg
   
    msg2    db    10
    len2    equ    $-msg2
   
    msg3    db    0
   

SECTION .bss

SECTION .data

    global _start
   
    _start:

                        ;for 32 bit divison, Processor assumes dividend to be of 64 bits, upper 32 in EDX, lower 32 in EAX
                        ;Divisor is supposed to be provided explitly, like div ebx -> divide EDX EAX by EBX
                        ;Quotient is stored in EAX and Remainder in EDX
                       
   
    mov eax, 1250                ;A number to be changed
    mov ebx, 10                ;To be divided by 10
    mov ecx, 0
   
    loopend:
        xor edx, edx
        div ebx                ;Divide it
       
        add edx, '0'
        push edx
        inc ecx
       
        cmp eax, ebx            ;CHeck whether quotient gets zero
        jle exit
       
        loop loopend            ;looping the loopend
   
    exit:
        mov eax, 1            ;Setting up the EXIT Ccall
        mov ebx, 0            ;Setting up the return status to OS
        int 80h                ;Yo ! Kernel do it.

Well, I seem to stuck at how to pop the stack because I do not know how to manage ecx for count and to pop simultaneously without pushing ecx on stack. I think the portion I have coded is working fine.

And sir. I lost my phone yesterday. I used to use internet through that phone only. Somehow, I managed to get net connection and now I am posting the progress.

Thanks
Title: Re: Help Needed
Post by: Frank Kotler on June 08, 2012, 01:50:40 AM
Good! Looks like you're trying a worthwhile optimization over what I showed you...

Code: [Select]
;Program to convert number to string
;Arc-PC
;7 June 2012

SECTION .data

    msg    db    'hey! I am there always', 10
    len     equ    $-msg
   
    msg2    db    10
    len2    equ    $-msg2
   
    msg3    db    0
   

SECTION .bss

SECTION .data

You probably want "section .text" here. There are some "flags" (just a bit in a dword) set in the linkable object file header which is passed on to the executable file header. One of them indicates "writeable" (otherwise it's "read only") and another indicates "executable". A ".text" section is supposed to be "read only" (the "writable" bit is clear) and "executable" (bit set to one). It won't hurt to make the code section writable (although there may be some "security" implications). My CPU, and apparently yours, will actually execute code even if the "executable" bit is clear. However, I understand that some newer CPUs have an "NX" bit which will prevent execution in a section that doesn't have the "executable" bit set in the section header (I can't confirm this from my own experience, but that's what I'm told). So I think it's "safer" to let Nasm set these bits the way they're "supposed" to be. Nasm "knows" several section names (see the Manual) - note that "SECTION" can be either upper or lower case, but the name must be lowercase!

Code: [Select]
    global _start
   
    _start:

                        ;for 32 bit divison, Processor assumes dividend to be of 64 bits, upper 32 in EDX, lower 32 in EAX
                        ;Divisor is supposed to be provided explitly, like div ebx -> divide EDX EAX by EBX
                        ;Quotient is stored in EAX and Remainder in EDX
                       
   
    mov eax, 1250                ;A number to be changed
    mov ebx, 10                ;To be divided by 10
    mov ecx, 0
   
    loopend:
        xor edx, edx
        div ebx                ;Divide it
       
        add edx, '0'
        push edx
        inc ecx
       
        cmp eax, ebx            ;CHeck whether quotient gets zero
        jle exit

Good! If eax is less than 10, the final digit is in eax and we can save a "div" (a very slow instruction) by stopping here. I don't think we want to stop if eax = 10! Also... "jl" is for signed integers, "jb" is for unsigned integers. Neither Nasm nor the CPU knows whether we intend an integer to be treated as signed or unsigned, we need to use different instructions. If the high bit of eax (bit 31) were set, "jl" would  take the jump, since eax would be negative if treated as signed. "jb" would take the jump all the way up to eax = 0xFFFFFFFF - eax would be "below", but not "less" (if that makes any sense). This is why the C language is picky about "types"! If you try to compare an "int" with a "uint", the compiler will squawk. It needs to generate different code for a signed comparison or an unsigned comparison. You can fix this with a "cast", but this could potentially hide subtle errors - better to make the variables the same "type" in the first place (I did not understand this when I was trying to teach myself C - I thought the compiler was being "nit-picky" with me - but now I understand "why" - an advantage to learning asm!). In this case, I don't see how eax could ever have the high bit set (potentially "negative" if we treat it as signed), so it shouldn't make any difference... but "jb" would be "more correct". "jl" should work, but I don't think you want the "e" - if eax is 10 exactly we need one more "div". (I don't think we actually want to jump to "exit" at this point, but that'll work itself out)

Code: [Select]
        loop loopend            ;looping the loopend

I don't think you want to "loop" at this point. You increment ecx to count each digit, "loop" decrements ecx each time. So "loop" will continue forever since we increment ecx, but ecx won't count digits either, since "loop" decrements it! If I understand where you're going with this, you want an unconditional "jmp" here. It won't become an infinite loop since you've got an "exit condition" elsewhere.

Code: [Select]
    exit:
        mov eax, 1            ;Setting up the EXIT Ccall
        mov ebx, 0            ;Setting up the return status to OS
        int 80h                ;Yo ! Kernel do it.

As I'm sure you know, we aren't quite ready to exit yet. When the "div" has gotten eax "below" (or "less than"... but not equal) 10, eax is our final digit. We still need to save (and count) this digit. We can "add '0'" either before or after pushing (or saving by another method) to "convert" number to character, as long as we do it someplace. You'll get to that...

It is entirely possible to use some other register besides ecx as a counter. "loop" uses ecx, but we can do the same thing with...
Code: [Select]
dec esi
; or sub esi, 1
; or lea esi, [esi -1]
jnz looptop

You actually use "loopend:" for this label - a terrible name for a label at the top of a loop! It doesn't matter to the "code" - the name is replaced by a number (the address of the label) - but for the sake of the poor "coder", "meaningful" names for labels or variables help a lot. (that's a nit-pick!)

As you observe, "push" is not a convenient way to save a value, since we're using the stack for our digits. What I did in the code I posted, was to save the "digit count" in another register. I used edx - since we're done with the "div" at this point, it's free for our use. Since I wanted to return the digit count, eax would have been convenient, but "stosb" uses al (a part of eax) and edi (es:edi actually, but in Windows/Linux/BSD segment registers all point to the same memory - this might not be the case in "your OS"... it isn't in dos!) "stosb" does:
Code: [Select]
mov [edi], al
inc edi
You can do the same thing, using other registers. I used "stosb" because it's short - one byte - but not particulary fast, and it depends on specific registers - there may not be much "advantage" to it.

As I mentioned, there are other ways of doing this. For example, we can get the digits in the "right order" by starting at the "end" of the buffer and working "backwards" as we get the digits, instead of pushing and popping them. This has the disadvantage that we don't know where the actual text representing the number starts. Since we're not using C, we can return more than one value. I've written a "number to text" routine that returns the "start of buffer" in ecx and the "length" in edx - all ready for the call to "print". Fairly "efficient" but potentially confusing, since it's not "standard" and definitely not "portable"!

Another approach is to avoid the slow "div" instruction entirely. It is possible to write a faster routine by using repeated "sub"s... or by using the reciprocal of 10 and using "mul" (this involves "fixed point" code). I don't have examples of either of these methods, but could probably(?) figure it out if I had to... Using "div" is slow, but "easy"...

You'll learn a lot by trying it yourself - learning what doesn't work is almost as valuable as learning what does work! So... "carry on!"

I can't help you with the phone problem. :)

Best,
Frank

Title: Re: Help Needed
Post by: grvtiwari on June 09, 2012, 09:33:53 PM
Well, I think I removed the mistakes. And yes, I did it. Only thing that now needs to be included in here is to input a number then changing it to actual number and then back to original. And sir, you showed me the routine number_to_string. I had to code my own version because I seriouslly didn't knew about 'stosb'. It will take a bit time to reach there. And sir, please do not do my home work *(as you did for number_to_string). I am here to learn. I will do it. just give me a hint, a path, i will cover it.
Code: [Select]
;Program to convert number to string
;Arc-PC
;7 June 2012

SECTION .data

    msg    db    'hey! I am there always', 10
    len     equ    $-msg
   
    msg2    db    10
    len2    equ    $-msg2
   
    msg3    db    0
   

SECTION .bss

    output    resb    20

SECTION .text

    global _start
   
    _start:

                        ;for 32 bit divison, Processor assumes dividend to be of 64 bits, upper 32 in EDX, lower 32 in EAX
                        ;Divisor is supposed to be provided explitly, like div ebx -> divide EDX EAX by EBX
                        ;Quotient is stored in EAX and Remainder in EDX
                       
   
    mov eax, 6250                ;A number to be changed
    mov ebx, 10                ;To be divided by 10
    mov ecx, 0
   
    loopend:
        xor edx, edx            ;Xoring EDX as it would contain the remainder, if not flushed, would screw the divison
        div ebx                ;Divide it
       
        add edx, '0'            ;Making it a Char
        push edx            ;Pushing Remainder on Stack
        inc ecx                ;Incrementing ECX
       
        cmp eax, ebx            ;CHeck whether quotient gets zero
        jl end
       
        jmp loopend            ;looping the loopend
   
    end:
        add eax, '0'            ;Final quotient is still waiting to be pushed, make it a char
        push eax            ;Push it on the stack
        inc ecx                ;Incrementing the ECX
        mov esi, output            ;Store the output adress
       
    combine:
        pop eax                ;Store the content
        mov [esi], eax            ;Move it to array
        inc esi                ;Increment it
        loop combine            ;loop till ECX hold it
       
    exit:
        mov byte[esi], 10        ;Setting up the Line Feed
        mov eax, 4            ;Setting up the Write Call
        mov ebx, 1            ;Setting up stdout
        mov ecx, output            ;Taking the addrss of output
        mov edx, 10            ;Wont be used I think. Linefeed would be used.
        int 80h                ;Print it.
       
        mov eax, 1            ;Setting up the EXIT Ccall
        mov ebx, 0            ;Setting up the return status to OS
        int 80h                ;Yo ! Kernel do it.

Thanks Again....
Title: Re: Help Needed
Post by: grvtiwari on June 10, 2012, 08:40:22 AM
I am referring a book on Assembly Language on LInux. It recommends us to use a "io.mac" and "io.o" file for complex input output procedure(in fact, every book I came across, pushed a io.o file  to use it to reduce the complexicity. This upsets me. When I am already ready to bang my head to learn the most complex low level language, why there is a need to hide any more details. Show me how exactly their read and write function works. ). I have a query regrading their procedure in io.o file. For example, there is a call
Code: [Select]
PutStr prompt_msgl ; request first number
Getint CX ; CX = first number
PutStr  prompt_msgl; request second number
Getint DX ; DX = second number

I understand how PutStr works. But I do not understand how this GetInt Works. Wait a minute I think I guessed how this GetInt works. There is no call instruction before GetInt which means it must be a Macro. Let me look up there. Then, What this means

Code: [Select]
%macro  PutInt  1
or this

Code: [Select]
%macro  GetInt  1

%ifnidni %1,AX

        push    AX

        call    proc_GetInt

        mov     %1,AX

      pop     AX

%else

        call  proc_GetInt

%endif

%endmacro
Title: Re: Help Needed
Post by: Frank Kotler on June 10, 2012, 06:14:51 PM
Sivarama Dandamudi? Sounds like his work. I haven't read his book, but I downloaded the example code including "io.mac" and "io.o". I haven't got source code for "io.o", and I understand it isn't in the book either... but we can disassemble it... It looks to me like Dr. Dandamudi originally wrote this for dos and converted it for Linux. It looks to me like he died before he was completely finished. In the macro you show, for example, "push ax"... That's a "legal" instruction, and works, but we'd get better performance if the stack were kept aligned at 4 bytes (for 32-bit code). There are a few 16-bit registers used in io.o, too. Not nice to speak ill of the dead, but this "isn't the way I would have done it."...

I agree with you about "hiding the details"! There's a reason this is (often!) done - there's a limited amount of time available in a formal "course", and if you show/teach/learn all the nitty-gritty details, you won't get very far before the end of the course! If the goal is to "obtain the program" (or just to "pass the course"), it makes sense to do this. If the goal is to "learn assembly language", it seems a shame to hide away the "good stuff". Inevitably, there's a "black box" at the end which we have to "just use" without understanding how it works (int 80h, for example), but I like to "see" as much as possible. Just my opinion...

Is there a "question" in this? Do you want to see the disassembly of "proc_GetInt"? Same idea as what you do, but he handles invalid input (and overflow) better.

Sorry I "did your homework" too much. I learn "by example" better than by "RTFM", so that's how I try to explain things. I don't know exactly what "hint" (or hints) you need, or I would limit it to that. "Just call printf" (or "just use io.mac/io.o") doesn't seem like enough. I'll try...

Best,
Frank

Title: Re: Help Needed
Post by: grvtiwari on June 10, 2012, 10:31:21 PM
Yes. It is the same book. I do not want to disassemble the code. Actually, I want to understand how he passed the parameters in GetInt AX. I mean it is not call by value(through registers) or through referance(through stack). And what %1 means here ?

That's all I want to know. I have a very bad habit. I want to code everything without any io.o . I mean when I say that I can code in assembly, then I should really be able to do that. After 10 years, I do not wish to seek help of a io.o to do simplest thing. It hurts the programmer in me.

Thanks. I will mention exactly what I require.
And I was expecting some comments on my previous number to string program.

Thanks.
Title: Re: Help Needed
Post by: Bryant Keller on June 11, 2012, 01:17:28 AM
I am referring a book on Assembly Language on LInux. It recommends us to use a "io.mac" and "io.o" file for complex input output procedure(in fact, every book I came across, pushed a io.o file  to use it to reduce the complexicity. This upsets me. When I am already ready to bang my head to learn the most complex low level language, why there is a need to hide any more details.

If you're goal is to learn assembly, then you should be focusing on learning the instructions, coding procedures and building various algorithms to help refine your understanding of the low level coding. The reason most people get detoured from assembly early on is because you can't just learn assembly. From the second that you want to display the results of data movements or calculations, you immediately have to become familiar with intricate components of whatever operating system you're using. And what's worse, each operating system does things different, so that part of the code is useless when you move between various operating systems (and sometimes between different versions of the operating system).

What this guy has done is to wrap the operating system specific stuff in macros so the learner can focus on assembly without having to deal with system specific things.

I don't exactly agree with the way he's done it. To be honest, the easiest method would be to teach the students assembly, and early on in the course provide them with the details of using calls to external procedures provided by a portable language (like C).

I understand how PutStr works. But I do not understand how this GetInt Works. Wait a minute I think I guessed how this GetInt works. There is no call instruction before GetInt which means it must be a Macro.

Yep, sure is.

Let me look up there. Then, What this means

Code: [Select]
%macro  PutInt  1

It literally means "declare a macro of the name 'PutInt' that takes 1 argument".

or this

Code: [Select]
%macro  GetInt  1

%ifnidni %1,AX

        push    AX

        call    proc_GetInt

        mov     %1,AX

      pop     AX

%else

        call  proc_GetInt

%endif

%endmacro

What we have here is a wrapper to a procedure that this guy wrote. I'll try to brake it down for ya.

Code: [Select]
%macro GetInt 1
Just like in the previous, we are declaring a macro named "GetInt" that takes 1 argument.

Code: [Select]
%ifnidni %1,AX
This looks more complex than it really is... NASM uses a % followed by a number to identify which macro argument it's referencing. The %ifnidni directive compares two identifiers against each other (ignoring case) and executes the following block of code if the two identifiers are not the same.

Code: [Select]
push AX
call proc_GetInt
mov %1,AX
pop AX

If the %ifnidni line finds that the argument passed to 'GetInt' was NOT the AX register, we must preserve the value of AX, call the procedure 'proc_GetInt' which returns with the integer in AX, store that integer in the memory location or register that was passed as the parameter to 'GetInt', and finally restore the AX register in case the code that called the macro had something valuable in AX.

Code: [Select]
%else
call  proc_GetInt
%endif

This part is an alternate compilation. If the argument to 'GetInt' actually was the AX register, then we don't have to do anything except call the procedure 'proc_GetInt', and since it returns the integer in AX, you're register is already updated.

Code: [Select]
%endmacro
This line specifies that we are done declaring our 'GetInt' macro.

That's all I want to know. I have a very bad habit. I want to code everything without any io.o . I mean when I say that I can code in assembly, then I should really be able to do that. After 10 years, I do not wish to seek help of a io.o to do simplest thing. It hurts the programmer in me.

You should get out of that habit because it's a very unrealistic goal. There are very few chances in a programmers life where he can do just "pure assembly". Usually that's when you're writing framework code that'll be used by others who will deal with the system specific issues. If you code on a computer, you're going to use other peoples code, you should get used too it. Think about it, say you stop using io.o, you'll still be using the operating systems API. If you get away from the operating systems API, then you're still using the BIOS API. It's an almost never-ending cycle which only prevents you from getting any real work done.

In fact, about the only way you can write code that isn't backed by someone else's API is if you break out Verilog/VHDL and design yourself a custom CPU then get a company to print you an ASIC and code exclusively for that system. That'd be a waste of time if you ask me..
Title: Re: Help Needed
Post by: Frank Kotler on June 11, 2012, 02:02:51 AM
Quote
That's all I want to know. I have a very bad habit. I want to code everything without any io.o . I mean when I say that I can code in assembly, then I should really be able to do that. After 10 years, I do not wish to seek help of a io.o to do simplest thing. It hurts the programmer in me.

Yeah... so what's the bad habit? :)

"%1", in this context, means the first parameter passed to the macro (%2 would be the second parameter, etc.). So he IS passing parameters (to the macro, not to "proc_getInt") in registers. I guess a variable would work, too, but you'd have to provide the '[]'s. "GetInt [my_number]" would(?) work, "GetInt my_number" would not. There's a pretty good(?) section on macros in the Nasm Manual. I like Nasm, but the macro syntax is uglier than a bulldog's hind end (IMO).

I didn't make any comment on your number to string program because I thought it was pretty good. One thing that could perhaps be improved, if you want to use it as a subroutine, is to pass the buffer - a "place to put it" - as a parameter rather than hard-coding it as "output". Maybe allow the number to be someplace besides eax - although you'll want it in eax for the "div" eventually. I'll look at it again to see if I can find any nits to pick, but basically, "Good job!"

Best,
Frank

P.S. I see Bryant disagrees with me on the "bad habit". No surprise, a lot of people disagree with me on that issue. If Guarav had told me in a personal message that he hopes to learn to write an OS eventually (which he did), would that change your opinion on "always have to use someone else's API"?
Title: Re: Help Needed
Post by: Keith Kanios on June 11, 2012, 06:16:36 AM
If Guarav had told me in a personal message that he hopes to learn to write an OS eventually (which he did), would that change your opinion on "always have to use someone else's API"?

Your rehashing of what Bryant said is taken out of a context that was about focusing on learning assembly language. In shorter words: straw man (http://en.wikipedia.org/wiki/Straw_man) :P

However, if you want to throw operating system development into the mix, then that means you'll have to accept a broadening of API to include any software accessible interface; whether that is a source-level API, ABI of the PC BIOS, or anything else which essentially exposes functionality in a "black box" (inputs and outputs) manner.

With respect to the above, Bryant already touched upon things that reinforces his premise, e.g. BIOS. Want to guess what word the last letter of the acronym ACPI (http://en.wikipedia.org/wiki/Advanced_Configuration_and_Power_Interface) represents? The list goes on, so I would agree that "always" (even as you put it) is still quite a sound assertion.

To step back a bit and refocus on the learning assembly language part, I would suggest using whatever you can to minimize worrying about I/O (the not-so-simplest things) so that you can focus on assembly language principles. Sometimes that means reading up on API documentation for a particular I/O system/library so you can observe your code in action.
Title: Re: Help Needed
Post by: Bryant Keller on June 11, 2012, 01:33:48 PM
P.S. I see Bryant disagrees with me on the "bad habit". No surprise, a lot of people disagree with me on that issue. If Guarav had told me in a personal message that he hopes to learn to write an OS eventually (which he did), would that change your opinion on "always have to use someone else's API"?

Not totally. Like I mentioned above:

Quote
I don't exactly agree with the way he's done it. To be honest, the easiest method would be to teach the students assembly, and early on in the course provide them with the details of using calls to external procedures provided by a portable language (like C).

This method would separate the user from system dependent issues as much as possible while still allowing them a method to view the results of their low level code. All without the worry of a possible system change crippling the courseware.
Title: Re: Help Needed
Post by: grvtiwari on June 12, 2012, 04:13:28 AM
Well, I agree to some of the points of everyone. For Bryant Keller sir, What if I understand myself a better, outstanding programmer just because I want to stand out of crowd. Today, with this system independent education technique, don't you see we all preparing a generation which won't know about read and write system call (the true core of assembly is being low level). I think with this, we will all lost low level knowledge. I am not a great student or a great philosopher either, I am just a student who is curious, very curious. I am in favour of low level system dependent thing. Everything should be simple but not simplest. Just because it is difficult, so it should be avoided, should not be done. I think low level knowledge is what makes a developer different and yes, a world-class programmer.

Keith Kanios Sir, I am again just a beginner, I want to grasp all the knowledge till the level of BIOS. It is only thing that would be available to me while trying to develop my OS. I was trying to learn Assembly from last 3 years. I belong to India, not so resource rich country. I had to download e-books. Everything book I tried, presented my a different syntax, a different macro file, a different assembler, a different OS. I finally decided to get over with it. I was quite acquainted with instruction because they do not change over any book. I decided to learn the few basic things from internet and through practice so as to not to get lost in any of sea of diff assemblers. I am making progress and believe me, I want to share all I know and I will.

Finally, Frank Kotler Sir, I do not why but I do share a kind of special bonding with you. It feels good to be interacting with a professional assembler developer, a developer who developed the software I use for assembling. You can count me as the one who would never leave your side. :) I am like that only. Just to let you know, I want to be like you, filled with all sort of knowledge and fledged with the capability to answer any question. I want to be coder. In my views, all ASM coders are true coder. I mean look at the IDEs today, many of us do not even know how a thing actually works. Before starting to learn ASM, I used to think I knew C language, now I am over with this misconception. Learning never stops, and I wish, it never does for me.

Sorry, for my bad English. Its not my native language. It has been on my mind since I made my first post.
Sorry, If I was rude anywhere, any time.

Thanks.
Title: Re: Help Needed
Post by: Rob Neff on June 12, 2012, 03:39:01 PM
Sir, I am again just a beginner

All levels of experience are welcome here.

...trying to develop my OS.

That is a very big topic for a beginner to tackle.  If you are going to persue that then, as a suggestion, get the source code for FreeDOS ( or Linux if you think you can handle that level of complexity ) and try to understand how the code causes the hardware to behave.  Good luck to you.
Title: Re: Help Needed
Post by: Frank Kotler on June 13, 2012, 06:31:23 PM
See? I told ya a lot of people disagree with me! :)

To clarify a couple of things... I am by no means a "professional assembler developer" - strictly a "dabbler". While it is true that I've got a (very!) little code in Nasm, I'm not a good C coder and prefer to leave it to others. I think of myself as more of an "advocate" than a "developer". Where it says "hero", "experienced beginner" would be more accurate! If you want to "be like me", try to be "like me, only not so lazy" - you'll get farther!

To get back more nearly on topic... "io.o" and GetInt/PutInt generally, "hides away" two things. One is the interface to the OS. We can't do much about that. The other is the number<->text conversion(s). That should be pretty "portable" (as long as we're using ascii) and I don't see why we shouldn't drag it out into the daylight and poke at it. How does it work? How else could it be done? Is there a "best" way?

Keith and Bryant both mention the importance of the "interface". Learning to use one as a beginner, and then to provide one. So what's a good "interface" to your "number to string"? Passing parameters in registers is easy in asm. Passing parameters on the stack would allow you to call it from C as well as asm. I would have said that a "regular C calling convention" would be best... but I see that for 64-bit code they've changed it back to passing parameters in registers... 32-bit code is fast becoming obsolete, so I dunno...

Just to refresh my memory, here's the last code you posted... with some comments marked with -->...

Code: [Select]
;Program to convert number to string
;Arc-PC
;7 June 2012

SECTION .data

    msg    db    'hey! I am there always', 10
    len     equ    $-msg
   
    msg2    db    10
    len2    equ    $-msg2
   
    msg3    db    0
   

SECTION .bss

    output    resb    20
;--> output_size equ $ - output ?

SECTION .text

    global _start
   
    _start:

                        ;for 32 bit divison, Processor assumes dividend to be of 64 bits, upper 32 in EDX, lower 32 in EAX
                        ;Divisor is supposed to be provided explitly, like div ebx -> divide EDX EAX by EBX
                        ;Quotient is stored in EAX and Remainder in EDX
                       
   
    mov eax, 6250                ;A number to be changed
    mov ebx, 10                ;To be divided by 10
    mov ecx, 0
   ;--> xor ecx, ecx is shorter, and I don't think it's any slower

    loopend:
        xor edx, edx            ;Xoring EDX as it would contain the remainder, if not flushed, would screw the divison
        div ebx                ;Divide it
       
        add edx, '0'            ;Making it a Char
        push edx            ;Pushing Remainder on Stack
        inc ecx                ;Incrementing ECX
       
        cmp eax, ebx            ;CHeck whether quotient gets zero
        jl end
       
        jmp loopend            ;looping the loopend
;--> perhaps "jae loopend" would replace "jl" and "jmp"
    end:
        add eax, '0'            ;Final quotient is still waiting to be pushed, make it a char
        push eax            ;Push it on the stack
        inc ecx                ;Incrementing the ECX
        mov esi, output            ;Store the output adress
       
    combine:
        pop eax                ;Store the content
        mov [esi], eax            ;Move it to array
;--> "mov [esi], al"?  you don't really want all four bytes of eax
;--> doesn't do any harm, 'cause you overwrite the unwanted bytes, but...
        inc esi                ;Increment it
        loop combine            ;loop till ECX hold it
       
    exit:
        mov byte[esi], 10        ;Setting up the Line Feed
        mov eax, 4            ;Setting up the Write Call
        mov ebx, 1            ;Setting up stdout
        mov ecx, output            ;Taking the addrss of output
        mov edx, 10            ;Wont be used I think. Linefeed would be used.
;--> no, it'll print all ten bytes! esi - ecx should give you the actual length

        int 80h                ;Print it.
       
        mov eax, 1            ;Setting up the EXIT Ccall
        mov ebx, 0            ;Setting up the return status to OS
        int 80h                ;Yo ! Kernel do it.

TightCoderEx has some thoughts here:

http://forum.nasm.us/index.php?topic=1410.0

Best,
Frank

Title: Re: Help Needed
Post by: Bryant Keller on June 13, 2012, 10:57:03 PM
Well, I agree to some of the points of everyone. For Bryant Keller sir, What if I understand myself a better, outstanding programmer just because I want to stand out of crowd. Today, with this system independent education technique, don't you see we all preparing a generation which won't know about read and write system call (the true core of assembly is being low level). I think with this, we will all lost low level knowledge. I am not a great student or a great philosopher either, I am just a student who is curious, very curious. I am in favour of low level system dependent thing. Everything should be simple but not simplest. Just because it is difficult, so it should be avoided, should not be done. I think low level knowledge is what makes a developer different and yes, a world-class programmer.

The reason for the platform dependency is for the classroom. When you have a room full of (200-300) students that you're trying to teach concepts of introductory level assembly, and some of the students own Windows, others have Linux, and others have Mac OSX. How are all these students going to validate their homework if their home computer won't run the examples they are building.

I'm all in favor of low level programming, truth is I don't really see a difference in the abstraction of those macros and the abstraction of those system calls. You talk about OS development with Keith, but those system calls aren't going to be there for you when you do OS development. That being the case, learning system calls is as useless learning these macros.