News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Hello and a question

Started by Rogare, September 30, 2009, 08:45:56 PM

Previous topic - Next topic

MichaelW

Here is your code with the (2) necessary corrections and some changes to demonstrate how you can use 32-bit instructions in 16-bit code, and two macro examples.

.MODEL SMALL
.386              ; enable 386 instructions
.STACK 100h
.DATA
    x DB ?
.CODE

;initProg PROC
;    mov ax,@DATA
;    mov ds,ax
;    ret
;initProg ENDP

startup MACRO
    mov ax,@DATA
    mov ds,ax
ENDM

;endProg PROC
;    mov ax,4C00h
;    int 21h
;    ret
;endProg ENDP

exit MACRO
    mov ax,4C00h
    int 21h
ENDM

printDot PROC
    mov ah,02h
    mov dl,2Ah
    int 21h
    ret
printDot ENDP

printC PROC
    ;pop dx       ; error
    mov ah,02h
    int 21h
    ret
printC ENDP

readC PROC
    mov ah,01h
    int 21h
    xor ah,ah
    ;push ax      ; error
    ret
readC ENDP

start:

    startup

    mov ah,02h
    mov dl,2Ah
    int 21h
    mov ah,08h
    int 21h

    call printDot

    ;mov dx,0048h
    mov edx,48h
    call printC

    mov ecx, 100000000
  @@:
    loopd @B

    ;mov dx,0069h
    mov edx,69h
    call printC

    call readC

    exit

END start


For parameters that are passed in registers, there are no stack operations involved. For the printC procedure the ASCII character code to be printed is in DX where the DOS Write Character function expects it.

For returning a value from a procedure, there are no stack operations involved. For the readC procedure to return a 16-bit integer you leave the value in the AX register and execute a RET instruction.

For both of the procedures, the misplaced push will "imbalance" the stack and prevent the procedure from returning to the caller. This happens because the RET instruction expects the return address to be at the "top" of the stack, and after the misplaced push whatever was pushed is at the "top" of the stack.
eschew obfuscation

Rogare

Thanks!
Just for clarification, but I think I got the idea.
If I put .386 I can use bigger registers. Stack size is still 16-bit.
3 questions:
1. You used somewhere a label called @@ and loopb'ed to @B - what is that?
2. Can I access the higher 16-bit of EAX by themselves? The lower part is divided into 8-bits and each can be accessed, what about higher part?
3. Let's say I do want to pass the whole EAX via stack. In theory I could push the higher 16-bit and the the lower 16-bit. How can it be done? (Almost like Q2, but I want to make sure I don't miss a thing.)

sinsi

If you put .386 after .model then things go better in real (16-bit) mode.
1. @@ - search for 'anonymous labels'
2. You can't directly access the top 16 bits, it usually takes a shift or rotate by 16
3. 'push eax'



startup MACRO
    mov ax,@DATA
    mov ds,ax
ENDM

exit MACRO
    mov ax,4C00h
    int 21h
ENDM

Since we're going all dotty with .model, why not use .startup and .exit  :lol
Light travels faster than sound, that's why some people seem bright until you hear them.

MichaelW

1) The @@: is an anonymous label. @B specifies the previous anonymous label, and @F specifies the next.

2) You cannot independently access the upper 16 bits of a 32-bit register, but you can use shifts and rotates to access them indirectly.

3) Pushing or popping a 32-bit value with a 16-bit stack is no problem - MASM will encode the instruction with the correct operand size. If you look in the code that FORTRANS posted at the POP ECX instruction, you will see that MASM encoded it with a 66h operand-size prefix. This prefix overrides the default operand size (16 bits for 16-bit code) so the instruction acts on a 32-bit operand.

And to enlarge on sinsi's comment regarding the position of the processor directive, if you place a .386 or higher processor directive above the model directive, then MASM generates 32-bit code where the default address and operand sizes are 32 bits. If you place a .386 or higher processor directive below the model directive, then MASM generates 16-bit code where the default address and operand sizes are 16 bits.

QuoteSince we're going all dotty with .model, why not use .startup and .exit

They were just quick examples. I use the .startup and .exit directives, and can't really understand why in 16-bit code with a model directive anyone would do otherwise, more than once.

eschew obfuscation

Rogare

Thanks all of you!
I'll play a bit and come back if I got more questions.

sinsi

Quote from: MichaelW on October 02, 2009, 11:51:05 AM
They were just quick examples. I use the .startup and .exit directives, and can't really understand why in 16-bit code with a model directive anyone would do otherwise, more than once.
Yeah, just joshing  :bdg

Minimum 16-bit exe?

.model small
.code
.startup
.exit
end

Light travels faster than sound, that's why some people seem bright until you hear them.

Rogare

Really? Then why in books they put the minimum with the mov's and the int?

MichaelW

QuoteThen why in books they put the minimum with the mov's and the int?

Probably because they want you to understand how to do it without the aid of these directives, the same reason behind starting with full segment definitions instead of the simplified segment definitions.
eschew obfuscation

Rogare

Hi again.
I assembled this program:
.MODEL SMALL
.STACK 100h
dotValue EQU 2Ah
.DATA
task DB 1
welcomeMsg DB "Enter task number: $"
endMsg DB "That's the task you asked for.$"
.CODE

; --- Macros from here

dot MACRO
mov ah,02h
mov dl,dotValue
int 21h
ENDM

newLine MACRO
mov ah,02h
mov dl,0Dh
int 21h
mov dl,0Ah
int 21h
ENDM

loadTaskId MACRO
mov ah,09h
mov dx,offset welcomeMsg
int 21h
mov ah,01h
int 21h
sub al,30h
mov task,al
newLine
ENDM

; --- Procedures

procA PROC
mov cx,05h
again:
mov bx,cx
doA:dot
dec bx
cmp bx,0000h
jne doA
loop again
procA ENDP

procB PROC
dot
newLine
procB ENDP

startTask MACRO
LOCAL end_macro
mov bl,task
cmp bl,01h
jne @f
call procA
jmp end_macro
@@: cmp bl,02h
jne @f
call procB
jmp end_macro
;@@: cmp bl,03h
; jne @f
; call procC
; jmp end_macro
@@:
end_macro:
ENDM

goodBye MACRO
mov ah,09h
mov dx,offset endMsg
int 21h
mov ah,08h
int 21h
ENDM

; --- Program Starts Here ---

start:
.startup

loadTaskId

startTask

goodBye

.exit

END


When running it and giving as input not 1 and not 2 - all is working. If I give 1 or 2 it does the work and asks again for task number.
Ideas?

Edit: Worse than that. When giving it input 1, it also does procB!

FORTRANS

Quote from: Rogare on October 02, 2009, 09:23:11 AM
I am afraid I can't read that code :)

  It is from a listing.  The code is to the right, the hex numbers
on the left is the address and machine code generated by the
assembler.

Quote
What do you mean by 2 blocks of code and "to set things up"?

  Ignore that, use what MichaelW showed you.  I set things up
with out documentation, so it is a bit contrived.

Quote
P.S.: For curiosity - what is the code you posted? Output of something? Different assembler's syntax?

  Listing file from MASM 5.0.  Here is the code that generated
the listing.


       POP     ECX             ;; 11 January 2008, break out columns
       SUB     ECX,1           ;; 3 => 1, bytes to pixels
       JA      RB_1b

       MOV     CX,[Padding]
       JCXZ    RB_3b


Quote
Edit: Another question:
When should I use a macro and when should I use a procedure? I know the difference, but could you give examples where one of the options is better than the other?

  That is a matter of taste.  They are similar.  Use what you like.
My preference is to use macros for small code snippets that are
used often.  And procedures for larger routines.  My main use of
macros is to use a mnemonic rather than a number to call DOS
functions.


; - - - - - - - - - - - - - - - - - - - - - - - - -
CRLF:   PUSH    AX      ; Save affected registers
       PUSH    DX
       MOV     DL,13   ; CR
       SCALL CONOUT
       MOV     DL,10   ; LF
       SCALL CONOUT
       POP     DX      ; Restore registers
       POP     AX
       RET

And the listing showing the macro expansion.  Note that
CONOUT becomes 2 to call the Console Output function.

    128                                ; - - - - - - - - - - - - - - - - - - -
    129 0051  50                       CRLF:   PUSH    AX      ; Save affected
    130 0052  52                               PUSH    DX
    131 0053  B2 0D                            MOV     DL,13   ; CR
    132                                        SCALL CONOUT
    133 0055  B4 02                 1          MOV     AH,DOSF_CONOUT
    134 0057  CD 21                 1          INT     21H
    135 0059  B2 0A                            MOV     DL,10   ; LF
    136                                        SCALL CONOUT
    137 005B  B4 02                 1          MOV     AH,DOSF_CONOUT
    138 005D  CD 21                 1          INT     21H
    139 005F  5A                               POP     DX      ; Restore regis
    140 0060  58                               POP     AX
    141 0061  C3                               RET


Regards,

Steve N.

Rogare

#40
Thanks for that - cleared some stuff.
Maybe you could also help me with the last problem I posted? Another thing I just found out - it never gets to the end_macro label when input is 1 or 2...

Edit: Bah... Forgot to write "ret" at the end of the procedures...
Edit 2: Is there a way to put the macros and procedures after the code itself? In .NET languages it just works and in C there is an empty definition earlier.
Edit 3: Question from Edit 2 still stands, but I got a bigger one.
I wrote this code:
dot MACRO
mov ah,02h
mov dl,dotValue
int 21h
ENDM

newLine MACRO
mov ah,02h
mov dl,0Dh
int 21h
mov dl,0Ah
int 21h
ENDM

procC PROC
mov bp,sp
xor cx,cx
mov up,ch
mov cx,0005h
again:
mov bx,cx
;-
mov ah,08h
int 21h
;-
doA:dot
dec bx
jnz doA
cmp cx,0001h
jne @f
mov al,01h
mov up,al
@@: mov al,01h
cmp up,al
jne nl
add cx,2
cmp cx,07h
jne nl
mov cx,01h
nl: mov dl,up
add dl,30h
mov ah,02h
int 21h
newLine
dec cx
jnz again
ret
procC ENDP


This code works fine, (up is DB, by the way) but when I tried replacing up with [bp-1] for some reason it was always reset to 98... It happened only after calling "dot" or "newLine". I tried putting the macro code inside the proc myself, still same problem.
Ideas?

Edit 4: Sorry for mass-editing. Solved problem 3, just said push cx at the beginning and changed to [bp-2] (and used ax instead of al when comparing). Still wants to know if I can put proc's and macros after the main.

dedndave

macros like to be declared prior to use - similar to equates
many times, we will put the macros in an include file, then reference that file at the beginning of the source
proc's can be moved to the bottom

Rogare

Oh, oh!
A great question you raised!
How do I include files? How can I put proces and macros outside the main program? How can I make a set of proces and use them later (like stdio.h in C and such things)?

dedndave

well - you can just put them in include files
or assemble them and create a library (with the obj files), if you like
include is easy
create the file - we usually put them in the masm32\include folder or in a specific project folder
then - at the beginning of the assembly file...

        include \masm32\include\MyIncFile.inc

whatever is in the inc file will be expanded in place of the "include" line
it is a good idea to put the .model, etc, first - then the includes - then the data and code segments

FORTRANS

Hi,

QuoteHow do I include files?

   That's easy, see the following code.


; - - - - - - - - - - - - - - - - - - - - - - - -
        .XCREF
        .XLIST
INCLUDE  DEFMS.ASM ; MACROs and MS-DOS definitions
        .LIST
        .CREF


   That turns off the cross reference and listing, include the
macros and equates, and then turns the listing and cross
references back on.

QuoteHow can I put proces and macros outside the main program?

   Just put them in a file and include it.


        RET     ; END FINDNAM4

CODE    ENDS
        INCLUDE PIXEL.ASM
        INCLUDE BMP2.ASM
        END     START


   At the end of this program I "INCLUDE" two more sets of
code.  Different versions of the program can use common
routines that way.  If I improve the shared code all versions
are "updated" without any edits.

Regards,

Steve N.

P.S.
I see Dave beat me to it.  Hope this adds something.

SRN