In Visual C's __asm, I'd like to do a jump to a location that's stored in a register, but it doesn't seem to work for conditional jumps, e.g. JAE. Ordinarily this works fine (if you use a label).
lea ecx, 0x0000001f[edx]
;jmp ecx ;ok
;jae EXIT_LOOP ;ok
jae ecx ; not ok "improper operand type"
Is there any way to do a jae with a register (or stack) variable with Visual C __asm? Maybe there's a different way to approach this problem (conditionally jump somewhere using a number, not label, known at compile time)?
Perhaps that's because there is no such opcode on the x86: you can't use a conditional jump except to a label. You probably want to:
...
jb skip
jmp ecx
skip:...
[Editing to add the label-less version]
This is ugly and sort of defeats one goal of using ASM (namely performance): note that JB (jump below) is equivalent to JC (jump on carry). Let A be the address to jump to if AE and B be the address if B:
...
sbb eax,eax,0 // propagate carry flag into register; eax == 0 or -1
and eax,B-A // eax = 0 or B-A
add eax,A // eax = A or B
jmp eax
You still need to figure out the addresses of where you want to go...
More involved tricks if you want to use other flags. You need to use the lahf or pushf instructions to get the flags into a processable position.
Ugh.
Related
Imagine I want to jump using an immediate (hidden behind a macro):
jmp label
How do I specify the width of the immediate so for example the jmp instruction for rel8 is executed. I tried:
jmp byte label
But it doesn't work. I'm working with the MSVC inline assembler.
The assembler will automatically choose the smallest encoding for the jump instruction. With MASM you can override this with jmp SHORT label, but the Microsoft inline assembler ignores the SHORT keyword.
Note that even with MASM, when using the SHORT keyword the label has to be defined somewhere else in the assembly file and be within –128 to +127 bytes of the jump instruction. Otherwise you'll get an error.
I tried to assemble a file with NASM, but it pointed to this line in the file:
mov al, byte ptr es:[bx]
saying:
error: comma, colon or end of line expected
I found a page on this site saying that NASM doesn't like the word "ptr" and it would be happy if I wrote:
mov al, byte es:[bx]
instead. So I took out the word "ptr" and NASM is still not happy. Here is what NASM gives me when I leave out the word "ptr":
warning: register size specification ignored
and:
error: invalid combination of opcode and operands
It's a catch 22! NASM is angry whether or not I put in the word "ptr". Can anybody help me with this?
I got it!
NASM is happy if I write:
mov al,byte [es:bx]
like Guy Sirton said. If I leave out the word "byte" from the instruction, here is what would happen. If the instruction is one like this:
mov al, [es:bx]
where NASM can see that I want to move one byte, since I'm storing it in al, it won't complain. But, if the instruction is one like this:
mov [es:bx],0xff
where NASM can't see how much memory I want to store 0xff in, it will give you such an error:
error: operation size not specified
It's important to know, especially if you are using this tutorial, that NASM won't except the regular way.
I am learning and I am a beginner in assembly language programming and we are currently learning about string printing and manipulating display memory. I'd like give the background before talking about the problem. We are making programs for the iapx88 (intel 8088) processor architecture, we are using the nasm assembler and the afd debugger. I use 32-bit Windows 7 Ultimate.
My problem is that I can't execute any of the string printing programs in the command prompt, even though the code runs correctly in the debugger. The attached images will help explain the problem better. Our instructor told us to run a full-screen dos program (like the editor) or to run the .com file of the program in the afd before executing the program in Dos. Neither of those tips has helped me. Here's one of the string printing programs which we've written:
; program in assembly to display 'hello world' on screen
[org 0x0100]
push cs
pop ds
jmp start
message: db 'hello world' ; string to be printed
length: dw 11 ; length of the string
; subroutine to clear the screen
clrscr: push es
push ax
push di
mov ax, 0xb800
mov es, ax ; point es to video base
mov di, 0 ; point di to top left column
nextloc: mov word [es:di], 0x0720 ; clear next char on screen
add di, 2 ; move to next screen location
cmp di, 4000 ; has the whole screen cleared
jne nextloc ; if no clear next position
pop di
pop ax
pop es
ret
; subroutine to print a string at top left of screen
; takes address of string and its length as parameters
printstr: push bp
mov bp, sp
push es
push ax
push cx
push si
push di
mov ax, 0xb800
mov es, ax ; point es to video base
mov di, 0 ; point di to top left column
mov si, [bp+6] ; point si to string
mov cx, [bp+4] ; load length of string in cx
mov ah, 0x07 ; normal attribute fixed in al
nextchar: mov al, [si] ; load next char of string
mov [es:di], ax ; show this char on screen
add di, 2 ; move to next screen location
add si, 1 ; move to next char in string
loop nextchar ; repeat the operation cx times
pop di
pop si
pop cx
pop ax
pop es
pop bp
ret 4
start: call clrscr ; call the subroutine
mov ax, message
push ax ; push address of message
push word [length] ; push message length
call printstr ; call the printsr subroutine
mov ax, 0x4c00 ; terminate program
int 0x21
This is how we have been told to make the .com file of the program:
nasm hello.asm -o hello.com -l hello.lst
I keep all the program files in the same folder 'Assembly' with the nasm assembler in my D: drive. And here's what happens when I try to execute the program in CMD:
First I type the name of the program: (http://i.imgur.com/rTWUxrJ.png)
After pressing 'Enter': (http://i.imgur.com/UWoH0LM.png)
I hope I have explained my problem well enough. I have tried to google the solution of this problem but I couldn't find one. If you guys could help me and tell me what I am doing wrong with my code, I would be very thankful to you.
Thanks.
You are using Windows to execute a DOS program. That may or may not work (it won't if you are using a 64 bit version of Windows). I suggest you to first run COMMAND.COM and then, from it, run your program.
UPDATE: I've just tried it but it didn't work. What did work is the following:
Run COMMAND.COM
Execute DEBUG program (the ancient DOS debugger)
From the DEBUG prompt, issue command db800:0
A hex dump of the text screen memory is shown: lots of 20 07 20 07
bytes
Issue "q" command to quit DEBUG
From the COMMAND.COM prompt, issue a CLS
Run your program. It works!
Seems like if the DOS VM included in Windows doesn't map the text screen memory until a EXE program is executed. Will test your program again, but converted to an EXE application to see if I'm right.
UPDATE2: forget about the EXE/COM issue. It's not that. It's just that the DOS VM doesn't start in text mode 3, which is what you are using. To switch to text color mode, add at the beginning of your program, right before calling clrscr the following code:
mov ax,3
int 10h ;select 80x25 color text mode
Ive been from tasm from a while and now migrating to nasm. One thing I notice is that given this code
mov ah,00h
int 16h
cmp ah,3Bh
je aaaa
jne bbbb
why is that if i compiled and link and run it in nasm, it doesnt produce a window like a command prompt that waits for my keyboard input (it just finishes executes by closing it)? before, this code works well in tasm and when i run it, it opens a prompt and then waits my keyboard entry.
(One thing I notice in tasm is that int 21h function 01,02,09 seems to work well but here in nasm, it doesnt). Thanks
Thanks
JMP $ LOOPS THE WINDOW INDEFFENITELY,
THIS IS BAD.
INSTEAD DETECT KEYPRESS FOR ENTER,
ADD A CONDITION LIKE A WHILE LOOP TO DETERMINE IF TO GO TO IT YOU CAN DETECT KEY PRESS TO BREAK THE CONDITION
I've written a simple bootloader in Assembly (NASM syntax), however when I run it in QEMU, the newlines show up like this:
This is my code:
Is there a way to stop 0Ah from pushing the lines forward?
.loop_top:
mov si, text_string ; Put string position into SI
call print_string ; Call our string-printing routine
loop .loop_top
jmp $ ; Jump here - infinite loop!
text_string db "This is my cool new OS!", 0Ah, 0
Well, obviously :-) your "print_string" subroutine takes the 0x0a seriously -- it's called "LF", and it does just that, advances to the next line.
My guess is that using 0x0a 0x0d will do the trick.
I believe that sending a \r will make the cursor return to the left side of the screen. So, you should use \r\n or something similar to make new lines.
I'm not sure without more details. I'm not for sure how your print_string procedure is implemented. If implemented by BIOS calls, such as by cycling through the string using int 0x10, AH=0x0E, then the above solution will work, or you can do something like using int 0x10, AH=0x03 to adjust the cursor position manually.