Hello,
I want to do a loop using Nasm syntax, but I don't know even where to start, then I'm asking for help here, but remember that I want resources to learn and try to build it, not just code. ;)

Best Regards,
Nathan Paulino Campos
Posted on 2010-06-04 09:44:35 by nathanpc
nathanpc,

To repeat some sequence of instructions one usually use branch instruction to transfer program control back to the start of that sequence. Unless repetition is terminated by other means, some conditional branch instructions are involved. The exact instructions depend on which kind of loop you're trying to implement: while, do…while/repeat…until, for/for each, etc.
Posted on 2010-06-04 09:59:51 by baldr
Oh, sorry for this, I'm already doing a loop like this:
loop:
    mov ah, 00h
    int 16h
   
    mov ah, 0eh 
    int 10h

    jmp loop

What I want is something like a if function for the input, like if the user input the text test and press enter, it will do something like print a char. ;)

Best Regards.
Posted on 2010-06-04 10:45:37 by nathanpc
nathanpc,

Store entered characters in some buffer inside loop, check for 13 to exit loop, then compare.
Posted on 2010-06-04 16:39:04 by baldr
I like to start with simple things, to complicate them later, then I've done this:
main:
   mov ah, 00h
   int 16h
   cmp al, "a"
   je got

got:
   mov si, msg
   call printf
   

; +------------+
; | Procedures |
; +------------+    
printf:
   mov ah, 0eh
   mov bl, 07h

   .nextchar
      lodsb
      or al, al
      jz .return
      int 10h
      jmp .nextchar

   .return
      ret

.data
msg db "Hello, World!", 0ah, 0ah

When I tried to test this, I got nothing. What is wrong?
Posted on 2010-06-06 12:24:48 by nathanpc
nathanpc,

Is it a complete source? Since there is no org 100h, I'll believe it's .Exe; then you need to initialize ds for lodsb to work as expected.

Is there anything supposed to be between je got and got:?

Where is the code to return control to OS?
Posted on 2010-06-06 13:13:00 by baldr
Sorry, my fault, lots of coffee, sleppy, 1 am, and I forgot the lodsb part, also it's not the complete code, just because I think that just those lines are important now, and there isn't anything betwen je got and the got label. Then I've corrected all, executed the code, then pressed the a character of my keyboard, then I waited about 10 seconds, nothing appeared on the screen, then I've pressed the a key another time, then the message was displayed, but just this: ello, World!, why there isn't displaying the H that starts the variable? Also, the message isn't displayed if I don't press the key two times, and also if I press it less than 10 seconds before the first press, I get anything. How could I solve this too?
Posted on 2010-06-06 16:06:02 by nathanpc
nathanpc,

Look, if you're able to determine which parts of the source are related to the problem, you must've been able to solve it yourself. ;-)
Posted on 2010-06-07 01:48:34 by baldr
I think that observation might not apply to everyone.
It appears that Nathan has little foundation knowledge - this is what allows us to determine solutions after having identified the nature, context and position of the issue at hand.
That's ok !! He can learn stuff as he rams headfirst into it, like we all did.
He's capable of learning, and he seems keen to do so  :thumbsup:
Posted on 2010-06-07 01:56:03 by Homer
Q: Why doesn't my program work?
A: Because something you believe to be true is not true!

I read that in an article about debugging Linux, but I think it applies generally. So what we need to do is figure out what we "believe is true" for every part of the program (this is the hard part!), and then check to make sure it *is* true.

You give a mystifying set of symptoms, Nathan! Why would ten seconds be important? I have no idea! Why does it work the second time? We might be able to figure that out, although I don't see it at the moment...

You don't show the "corrected" code, so I'll try with what you last posted. Starting with "pre code", before what you show. As baldr points out, we don't really know what "kind" of code this is. If it's a .com file, it needs to start with "org 100h". "org" sounds like "organization" to me (something I'm very bad at!), but it means "origin" - where (not when) the code begins. Nasm does not know this, and assumes zero unless we tell it otherwise. "Not true" in a .com file! Dos loads a .com file at offset 100h... in a segment of its own choosing (lowest one free, usually). It then sets all our segment registers to this segment. This is "not true" for other file types! So a .com file needs to know "100h", but we don't need to initialize segregs.

Baldr guesses maybe .exe. I'd expect to see a "..start" label if that were the case. We would need to initialize segment registers in that case. ".data" is not a segment directive (if you "believed this is true", it isn't), so your data is in the code segment. I think .exe would be a really bad choice for this, so I'm going to ASSume "not true". (if I'm wrong, we can come back to it)

Last I knew, you were trying to do this in a bootsector. If "true", bios loads our code to 7C00h. Due to the way "segmented addressing" works, this address could be represented as segment 0, offset 7C00h, or segment 7C0h, offset 0. Exact same address! You don't show "org 7C00h", but maybe it's there. If "true", you need to initialize segregs to 0. If "not true", you need to initialize segregs to 7C0h. Either will work. Your bios *may* leave ds and es at 0, but this would be "not true" in other machines.

I should mention that much code will run fine without these conditions being "true". It is not obvious to beginners, but almost all "jmp" varieties, and all conditional jumps, and "call", use "relative addressing". We write "jmp target", and it disassembles as "jmp (address of target)", but if you look at the bytes actually emitted, you'll see not "opcode, address of target" but "opcode, distance to target" (distance can be plus or minus). This means that such code will run without knowing what address it's running at ("position independent code"). It doesn't need to know what actual address "printf" is at, since it knows the distance, and that's what the actual operand bytes are. As soon as you do "mov si, msg", however, it must be "true" that ds:msg points to the correct address! Segment and offset must be "synchronized".

Whew! Now I think we're ready to discuss the code you show:


1 main:
2    mov ah, 00h
3    int 16h
4    cmp al, "a"
5    je got
6
7 got:
8    mov si, msg
9    call printf
10   
11
12 ; +------------+
13 ; | Procedures |
14 ; +------------+   
15 printf:
16    mov ah, 0eh
17    mov bl, 07h
18
19    .nextchar
20      lodsb
21      or al, al
22      jz .return
23      int 10h
24      jmp .nextchar
25
26    .return
27      ret
28
29 .data
30 msg db "Hello, World!", 0ah, 0ah


1) IMHO, "main" is a horrible name for an entrypoint that isn't a real "C-style main" - that is, called by some other code that has done "expected initialization". I'm assuming this is "not true" here. It doesn't matter - "main" has no particular meaning in asm, but... you see baldr trying to guess what "kind" of code this is by seeing "org 100h" or not... seeing "main" is liable to give us the wrong idea. Not important, just one of my little rants. :)

You're okay up to about "line 6", I think. If al is 'a', you jmp to "got:". Good. What happens if it's not 'a'? Execution continues without taking the jump, and "falls through"...  into "got:". Probably not what you intended. The "if not" probably wants to jump back and get another key. I'd name that label "get_key:" instead of "main:", and "jmp get_key" here.

8) We "believe it is true" that the text "msg" gets translated into the address (the offset part of the address) of our message. We can verify this by looking at a disassembly of our program. "ndisasm myprog[.ext]" will dump a disassembly to the screen. Okay for short programs, but you may want to pipe it into a "pager" - ndisasm myprog | more (you guys still haven't got "less"?) or redirect output into a file - ndisasm myprog>myprog.dis or so... If you've got an unseen "org" in your program, tell ndisasm about it - ndisasm -o 7C00h myprog, or whatever. You should see "mov si, (some number)" - you can identify where the message starts in a disassembly by the sudden appearance of "garbage code" you didn't write following(? we hope) the code you did write. If the numbers don't match, there's the problem. There are, of course, other tools capable of doing this (better?), but I "believe it is true" that if you've got nasm, you've got ndisasm...

10) What happens after printf returns? You "fall through" into printf again! This time, si no longer points to "msg" (if it ever did), but after whatever we've just printed (if anything - even encountering a zero would increment si - this may account for why it works "second time"). Also, this time, printf hasn't been "call"ed, so there's no return address on the stack. When you get to line 27 - ret - who knows where we go! Since you apparently get a chance to hit 'a' again, we apparently get to "get_key:" (nee "main:") again somehow. Perhaps by such a detoured route that it takes "ten seconds"? Seems unlikely, but "anything can happen". You need to do something when printf returns, besides fall into it again! Maybe jump back to get_key/main, or maybe this would be a good place for the "return control to OS" code that baldr mentions. If you haven't got an OS, go into an infinite loop - jumping back to get_key would effectively be an infinite loop - or int 19h will restart your system.

17) As I recall, the last video bios I tried it on didn't care what was in bl or bh - I got white text to video page zero, regardless. But bh is "supposed" to indicate the video page to write to. To be "true" for all machines, I'd use "mov bx, 7" (or another color, if it matters) to make sure bh is set to video page zero (if it matters).

20) lodsb loads al from (and increments si). At this point, we "believe it is true" that ds:si points to our message. Both ds and si need to be "right". If this is "not true", the problem "appears" at this point, but was actually "caused" by far-away code where we told Nasm the correct "org" and initialized segregs... or didn't.

29) This does nothing. There are macro files that can be "%include"d that would turn ".code" and ".data" into "section .text" and "section .data", but I don't "believe it is true" that you're using them. Without it, it's just an unused label. Without a colon, Nasm may complain about it (also lines 19 and 26), but it does no harm.

30) Did you really mean "0ah, 0ah" or "0dh, 0ah". Doesn't matter, I guess.

One more very minor point: way back at line 2. Strictly speaking, 0 is an "old" int 16h function - intended for the AT (80 key?) keyboard. There are a few key combinations on a modern keyboard that it won't pick up. I was trying to write a "draw" program, and was using "control-up-arrow" (etc.) to "jump 10 pixels". Worked for control-up, but not for control-down (or the opposite). Drove me crazy trying to figure out what I'd done wrong! The "new" interrupt for the XT (88 key?) keyboard is "mov ah, 10h". That fixed it. It'll be a long time before you notice the difference, but I thought I'd mention it...

I strongly suspect the reason you're not seeing the expected output is that ds or si (or both) don't have the correct values, but you want to fix the "flow" for "if not 'al'" and after the return from printf, too. Then it should work... if everything I believe is true is actually true. :)

Best,
Frank

Posted on 2010-06-07 09:06:23 by fbkotler
Homer,

I understand, but why? This kinda looks like if I come to a car repair workshop and say: "My car has problems with steering and brakes. I brought the steering wheel and the pedal. Can you fix it?"
Posted on 2010-06-07 12:31:33 by baldr