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

dedndave

always good to have more than one approach, Steve
i didn't think to mention turning off the listings
i use .nolist - must be a newer syntax

Rogare

Okay, let's see if I got it.
I create a normal ASM file with proces and macros.
I create an ASM file for my program and writes "include" (with xlist and all) with the path of the first ASM after model and stack before data and code?
Can I put the included file also somewhere in My Documents and such (for ex.: where the program's ASM file is), or only in masm32/includes ?

dedndave

you can put it where you like, as you are going to specify where it is located in the include directive
choose someplace that makes sense
that file has to be in place whenever you want to assemble the program
if you look in the masm32\include folder, there are several examples to look at
as a side-note, there is an environment variable named INCLUDE for masm
if you specify c:\masm32\include in the INCLUDE path, masm will look there for inc files that do not have a specific path
then, all you need to have in the program file is

        include MyIncFile.inc

masm will look for it in the INCLUDE path

MichaelW

IIRC procedures must be defined or declared above the point at which they are called only if they are called with invoke. The MASM equivalent of a declaration is a prototype done with the PROTO directive.
eschew obfuscation

Rogare

#49
I tried creating a program that gets a number and return its ASCII match (65 -> A, 99 -> c).
It returns wrong values, any ideas why?
Code:
---
Just after I left the house I found the first problem with my code. If it won't work after that, I'll ask again.

Rogare

Here is a new problem.
I tried working with structures (did work for a while), but then I wanted to give a structure as an argument for a procedure. The following example should print on the screen "1" or "0" (I suspect that I switched the 1 and 0 there...) and then wait for use input. It doesn't do that.
Here is the code:
.MODEL SMALL
.386
.STACK 100h
myNOP EQU 20h
book STRUC
the_name DB 50 DUP(20h)
author DB 50 DUP (20h)
noPages DW 0000h
book ENDS
.DATA
myBook book <"1984$","George Orwell$",250d>
.CODE
.startup
mov bx,21h
mov [myBook.noPages],bx
lea bx,myBook
push bx
mov bx,myNOP
push bx
call book_canbe
pop dx
add dl,30h
mov ah,02h
int 21h
mov ah,08h
int 21h
.exit

book_canbe PROC
mov bp,sp
mov di,[bp+4] ;book address
mov cx,[bp+2] ;page number
mov bx,[di+book.noPages]
pop ax
pop ax
cmp bx,cx
jb return_false
push 0001h
jmp the_end
return_false:
push 0000h
jmp the_end
the_end:
ret
book_canbe ENDP

END

Ideas?

dedndave

first of all, the END directive should name the entry point

start:
.startup
.
.
.
end start

the next thing i see is the book_canbe procedure makes a real mess out of the stack
when you call a procedure, the return address is pushed onto the stack
if you expect the procedure to return, the RET instruction needs to POP off a valid code address
you have popped that return address into AX and not restored it

the other thing i see is the use of the stack frame
it is good practice to save the BP value so that other procedures may call this one without destroying their stack frame
in this case, it is probably ok, but it is just a good habit to push the BP value prior to setting the frame
once the frame has been established, the pushed parameters may be accessed by using bp

SomeProc PROC
        push    bp
        mov     bp,sp
.
        mov     ax,[bp+4]   ;pushed parm into AX
.
        leave               ;same as mov sp,bp then pop bp
        ret
SomeProc ENDP

one final note
if you are going to push a parameter onto the stack prior to a call, the stack needs to be cleaned up afterward
you can do this one of 3 ways:

        push    SomeParameter
        call    SomeProc
        pop     ToSomeplace

or

        push    SomeParameter
        call    SomeProc
        add     sp,2            ;discard the stack parm

the third way is to let the RET instruction clean up for you

        ret     2               ;return, then discard 2 stack bytes

EDIT - the LEAVE instruction above may be replaced with POP BP if the procedure has a balanced stack
in some cases, it is faster and more convenient to let the LEAVE instruction balance the stack for you

Rogare

Puff... I always forget about the return address things in stack...

I also found out that .startup is instead of start: and END start. Tried to add this and got errors saying it is ignored because of .startup.
If anyone is interested, here is the code (and it works! - returns 1 just as I wanted it to):
.MODEL SMALL
.386
.STACK 100h
myNOP EQU 20h
book STRUC
the_name DB 50 DUP(20h)
author DB 50 DUP (20h)
noPages DW 0000h
book ENDS
.DATA
myBook book <"1984$","George Orwell$",250d>
.CODE

.startup
mov bx,21h
mov [myBook.noPages],bx
lea bx,myBook
push bx
mov bx,myNOP
push bx
call book_canbe
pop dx
add dl,30h
mov ah,02h
int 21h
mov ah,08h
int 21h
.exit

book_canbe PROC
mov bp,sp
mov di,[bp+4] ;book address
mov cx,[bp+2] ;page number
mov bx,[di+book.noPages]
pop dx
pop ax
pop ax
cmp bx,cx
jb return_false
push 0001h
jmp the_end
return_false:
push 0000h
the_end:
push dx
ret
book_canbe ENDP

END

Rogare

Another question!
How can I dynamically allocate memory? For example: dynamic array's size.

dedndave

there are a few ways to do it
perhaps the simplest way is to use the heap functions

GetProcessHeap
http://msdn.microsoft.com/en-us/library/aa366569(VS.85).aspx

HeapAlloc
http://msdn.microsoft.com/en-us/library/aa366597(VS.85).aspx

HeapFree
http://msdn.microsoft.com/en-us/library/aa366701(VS.85).aspx

oops - those are 32 bit - lol

for 16-bit, there is an INT 21h function call to allocate memory
what you need is a good reference for INT 21h
if you google around for Ralf Brown's Interrupt List, it will tell you many things
it is a 6-part zip

here you go...
http://www.cs.cmu.edu/~ralf/files.html

Rogare

Thanks, I'll google in a sec. But first I got another problem.
I got an include file with a structure and a procedure. Where should I put the include statement? I tried just before the .DATA, got this error (several times):
error A2034: must be in segment block
Where should it be?

dedndave

the procedure needs to be in the .text segment (in the include)
the structure definition should not matter
but, the structure declaration needs to be in .data or .data?

i usually list all includes after my model/processor directives

Rogare

I didn't understand what you wrote, but you gave me the idea just to put .CODE before the procedure.
It works, but it'll be nice to understand what you meant.

Ossa

.text is an alias for .code (it is the usual name of the code segment in the PE header under 32 bit).

The procedure has to go in the code segment because it is code - also, the structure definition should (I'm not sure it has to) go before the first use of it. For this reason it is not usual (in the greater world outside this board) for include files to contain code. The convention is that includes (.inc in ASM, .h in C/C++, etc) to contain definitions/prototypes/externs/etc but do not include code or declarations. If you want to split your code up, you then put it in several different files and assemble each one into a separate object file and link them together. Despite this, a disturbing number of people in the ASM community have code in INC files that they include - mainly because it is easier to do - and this is great for smaller projects but once you start on a large project it really becomes quite a bad way to do it.

Hope that actually makes sense,
Robert
Website (very old): ossa.the-wot.co.uk

FORTRANS

Hi,

   As you can see in the example I posted, you can include a file
outside of a segment.  I ended the code segment and then
included the two files just before the end statement.  The
files have their own segment definitions for code and data.

  The first include in that post was for macros and symbol
definitions.  It was included before any segment definitions
as it contains no code or data.

   As Robert noted, including files that contain code (and/or
data?) is probably not the best method if you have a big
project.  In that case a "makefile" assembling and linking
together separate files is probably better.  If you have a
set of commonly used routines, a library may be useful.

Regards,

Steve N.