The MASM Forum

General => The Campus => Topic started by: shekel on May 23, 2015, 12:51:36 PM

Title: Make procedure
Post by: shekel on May 23, 2015, 12:51:36 PM
Sorry by my English

Im working with files.. in my case i want to make a function that count the lines of the file and other function that giveme the text in the line..

Im doing this:

ReadFile proc Line:DWORD
LOCAL szFile[MAX_PATH]:DWORD
LOCAL hRead:HANDLE
LOCAL hMemory:HANDLE
LOCAL pMemory :DWORD                             
LOCAL SizeReadWrite :DWORD     
LOCAL sizee: DWORD             

LOCAL CurrentLine:DWORD   

invoke lstrcpy, addr szFile, chr$("C:\file.txt") 
invoke CreateFile, addr szFile,GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, 0
mov hRead, eax
invoke GetFileSize, hRead, NULL
mov tamano, eax
invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT, addr sizee
        mov  hMemory,eax
        invoke GlobalLock,hMemory
        mov  pMemory,eax 
invoke ReadFile, hRead, pMemory, addr tamano , addr SizeReadWrite, 0

; new line --> '0D 0A'
invoke lstrlen, pMemory
mov ecx, eax
mov esi, pMemory 
xor edx, edx
letter:
mov al, [esi]
.if al == 0Dh
inc esi
mov al, [esi]
.if al == 0Ah
; line
inc edx             ; HERE is the number of lines
mov bx, 0
mov [esi-1], bx
.endif
.endif
inc esi
loop letter

mov eax, [Line]
dec eax
.if eax > edx
xor esi, esi
ret
.endif

mov [CurrentLine], 1
mov esi, pMemory
mov ecx, edx
line:
mov eax, [CurrentLine]
.if [Line] == eax
mov ecx, 1
.else
invoke lstrlen, esi
add esi, eax
add esi, 2h
inc [CurrentLine]
.endif
loop line




invoke MessageBox, NULL, esi, chr$("aa"), MB_OK

invoke GlobalUnlock, hMemory
invoke GlobalFree, hMemory
invoke CloseHandle, hRead

ret

ReadFile endp


I dont know if this is a beautiful way.. but it works..

If now i want get the count of the lines, for example, getCountLines proto, i need rewrite the createfile, open memory, read file, etc..

Or how can i do...
pseudocode:

       getCountLines proc
            invoke MyFunctionThatOpenFileAndReserveMemory
            mov eax, HERE_IS_THERE_MY_LINES
            invoke CloseAllTheHandlesOfTheFileAndMemory
       getCountLines endp

       getLine proc Line:DWORD
            invoke MyFunctionThatOpenFileAndReserveMemory
            mov esi, MOVE_HERE_THE_TEXT_OF_THE_LINE
            invoke CloseAllTheHandlesOfTheFileAndMemory
       getLine endp

Or if i create a single function with one "parameter" and if this value is "-1" that meaning that want the count of the line??


Sorry for do this question and my bad english but im trying to learn
Title: Re: Make procedure
Post by: rrr314159 on May 23, 2015, 02:30:13 PM
shekel no need to apologize your English, it's quite good, almost seems like a native speaker pretending otherwise!

Quote from: shekelbut it works

- But it can't work.

The proc can't be named ReadFile - in fact you call the Windows function ReadFile in it.
And, "tamano" (strange name) is a "Symbol not defined" - will give an error.

But this proc that you wrote yourself works for you; and, it's a pretty sophisticated piece of code, so clearly u know MASM well! That's great! You've merely made a couple typos posting it (the two mentioned above, couple more also). Just fix it up so we can run it also, (include a start: routine calling it) then we can make trivial changes to make it CountLines.
Title: Re: Make procedure
Post by: shekel on May 23, 2015, 02:59:49 PM
Thats truth...  in my file the procedure is called 'ReadIpFile' because i save few ips in that file but when i posted i decided delete the 'ip' part.
In my language 'size' is 'tamaƱo'
Title: Re: Make procedure
Post by: rrr314159 on May 23, 2015, 03:08:00 PM
Huh! That's pretty convincing!

Now if you could make the necessary changes, and just call the routine from a start: label (takes a few lines), post the results, we'll have something very easily modifiable to Count Lines
Title: Re: Make procedure
Post by: shekel on May 23, 2015, 03:20:26 PM
Its better way?


start:
  invoke CountLinesIpFile
  --> eax = num of lines
  invoke ReadIpFile, 3
  --> esi = have text of line number 3
  --> if not have this line esi = {empty}
--------

CountLinesIpFile proc

invoke ReadIpFile, -1
inc eax
ret

CountLinesIpFile endp


ReadIpFile proc Linea:DWORD
LOCAL szFile[MAX_PATH]:DWORD
LOCAL hRead:HANDLE
LOCAL hMemory:HANDLE
LOCAL pMemory :DWORD                             
LOCAL SizeReadWrite :DWORD     
LOCAL tamano: DWORD             
LOCAL LineaActual:DWORD   
 
invoke lstrcpy, addr szFile, chr$("C:\file.txt")

invoke CreateFile, addr szFile,GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, 0
mov hRead, eax
invoke GetFileSize, hRead, NULL
mov tamano, eax
invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT, addr tamano
    mov  hMemory,eax
    invoke GlobalLock,hMemory
    mov  pMemory,eax 
invoke ReadFile, hRead, pMemory, addr tamano , addr SizeReadWrite, 0

invoke lstrlen, pMemory
mov ecx, eax
mov esi, pMemory 
xor edx, edx
letra:
mov al, [esi]
.if al == 0Dh
inc esi
mov al, [esi]
.if al == 0Ah 
inc edx
mov bx, 0
mov [esi-1], bx
.endif
.endif
inc esi
loop letra

mov eax, [Linea]
.if eax == -1
push edx
invoke GlobalUnlock, hMemory
invoke GlobalFree, hMemory
invoke CloseHandle, hRead
pop eax
ret
.endif
dec eax
.if eax > edx
xor esi, esi
ret
.endif

mov [LineaActual], 1
mov esi, pMemory
mov ecx, edx
linea:
mov eax, [LineaActual]
.if [Linea] == eax
mov ecx, 1
.else
invoke lstrlen, esi
add esi, eax
add esi, 2h
inc [LineaActual]
.endif
loop linea




invoke MessageBox, NULL, esi, chr$("aa"), MB_OK


invoke GlobalUnlock, hMemory
invoke GlobalFree, hMemory
invoke CloseHandle, hRead

ret

ReadIpFile endp
Title: Re: Make procedure
Post by: shekel on May 23, 2015, 03:26:47 PM
A simple question...

If i push a reg inside a procedure and 'forget' recover this value with pop its bad for my application ??
Title: Re: Make procedure
Post by: rrr314159 on May 23, 2015, 03:34:12 PM
Hmmm ... do you have MASM32? How do you run your code? This still won't work, of course. IF you're using masm32, you need at least these lines at the top:

include \masm32\include\masm32rt.inc

CountLinesIpFile proto
ReadIpFile proto :DWORD

.code


And then, keep going and get it to run (error messages will make it clear what's needed). Once it's running it's trivial to make it Count Lines .. but until it runs, can't do anything with it

While I was typing you asked:

Quote from: shekelIf i push a reg inside a procedure and 'forget' recover this value with pop its bad for my application ??

- Sure is, it will crash (go off into deep space, as we say)
Title: Re: Make procedure
Post by: dedndave on May 23, 2015, 08:38:40 PM
if you leave the stack unbalanced, all sorts of bad things happen
eventually, you will get some sort of exception (program crash)
probably sooner than later - lol

here is a simple example of how to call a function with INVOKE
;###############################################################################################

        INCLUDE    \Masm32\Include\Masm32rt.inc

;###############################################################################################

MyFunc PROTO :DWORD,:DWORD

;###############################################################################################

        .DATA

szMyString db 'Hello World!',13,10,0

;***********************************************************************************************

;       .DATA?

;###############################################################################################

        .CODE

;***********************************************************************************************

main    PROC

        INVOKE  MyFunc,offset szMyString,3

        print   chr$(13,10)
        inkey
        INVOKE  ExitProcess,0

main    ENDP

;***********************************************************************************************

MyFunc  PROC USES EBX ESI lpString:DWORD,nCount:DWORD

    mov     ebx,nCount
    mov     esi,lpString
    .if ebx
        .repeat
            print   esi
            dec     ebx
        .until ZERO?
    .endif
    ret

MyFunc  ENDP

;###############################################################################################

        END     main
Title: Re: Make procedure
Post by: Farabi on May 28, 2015, 09:44:16 AM
Hi, when a program hit "ret" instruction, the address it point is the last one on the stack frame. So, if you forget to pop, it will execute a wrong address.



Push addr MyProcedure
ret

MyProcedure proc


ret
MyProcedure endp


That code will jump to myprocedure and start the termination by returning it to the first caller, the OS.
Title: Re: Make procedure
Post by: jj2007 on May 28, 2015, 05:40:40 PM
Quote from: shekel on May 23, 2015, 03:26:47 PMIf i push a reg inside a procedure and 'forget' recover this value with pop its bad for my application ??

Yes and no 8)

include \masm32\include\masm32rt.inc

.code
MyProcedure proc somearg
  push eax
  push ecx
  push edx
  print somearg ; use Console build
  ret
MyProcedure endp

start: invoke MyProcedure, chr$("See the text?")
MsgBox 0, "Hello World", "It works:", MB_OK
exit
end start


Build it a) with standard Masm, b) with JWasm, then launch Olly for both and see why they behave differently.
In any case, you should balance the stack.
Title: Re: Make procedure
Post by: rrr314159 on May 28, 2015, 07:26:36 PM
@jj2007,

I'll be darned. I guess u can't call it a bug, though? After all,

Quote from: jj2007In any case, you should balance the stack.

does anyone else in the world know this obscure little difference ... ? even Japheth and Habran might not

good catch :t
Title: Re: Make procedure
Post by: jj2007 on May 28, 2015, 08:02:02 PM
Japheth and a few others (Dave, qWord, Hutch, Habran, ...) surely know it.
A bug? No. Masm is too tolerant, maybe.
Title: Re: Make procedure
Post by: nidud on May 28, 2015, 10:25:57 PM
deleted
Title: Re: Make procedure
Post by: rrr314159 on May 29, 2015, 02:57:44 AM
Obviously you're right a lot of thought was put into JWasm! But only timing is examined here, no explicit mention of fact that if stack is unbalanced in a proc that's OK in MASM not JWasm; only locals on the stack were considered.

It's not completely ridiculous to allow unbalanced stack in a proc ... in fact that's sort of what a stack frame w/ locals is. May be "too tolerant", not clear.

Unfortunately it doesn't help the cause when asking people to switch to JWasm: legal ML code can explode! Wonder how many of these little "gotchas" there are? And imagine chasing down a bug like that in a prog with thousands of lines - they'd definitely go back to ML
Title: Re: Make procedure
Post by: nidud on May 29, 2015, 03:19:16 AM
deleted
Title: Re: Make procedure
Post by: jj2007 on May 29, 2015, 03:52:18 AM
Quote from: rrr314159 on May 29, 2015, 02:57:44 AMUnfortunately it doesn't help the cause when asking people to switch to JWasm: legal ML code can explode! Wonder how many of these little "gotchas" there are? And imagine chasing down a bug like that in a prog with thousands of lines - they'd definitely go back to ML

Going back to ML is not a good option; an unbalanced stack means the coder has lost control (unless he did it on purpose). Worst case is someproc uses esi edi ebx arg1, arg2 - you are trying to preserve non-volatile regs but you are getting back garbage - and it may take a long time until that actually produces a fat problem, usually on the client's premises :icon_mrgreen:

P.S.: Gotchas (http://web.archive.org/web/20140202233143/http://www.japheth.de/JWasm/Manual.html#CHAPMASMBUGS)
Title: Re: Make procedure
Post by: rrr314159 on May 29, 2015, 04:15:40 AM
Of course the coder may have done it on purpose. In fact I do something like this in my "invoke macros". There I'm explicitly "leave"ing but if I'd known this about ML, I might conceivably have used their proc. If so, then years later I tried to switch to JWasm and it blew up ... I'm thinking of a case like that, where somebody tries his large ML prog under JWasm (because, for instance somebody like me recommends it) and it blows up for this reason. He's not going to want to chase that down (he did it years ago, and doesn't even know what the problem is anyway).

It occurs to me that one of the switches -Zm, -Zne, -Zv8 might force compatibility on this issue, don't have time to check it. But I'd say this is the sort of thing one of those switches should do: restore the (presumably) inferior ML way if coder wants it.

Some of those "gotchas" u link to are in fact gotchas, not all. Whenever a "problem" is "fixed" such that the improved JWasm won't run the old code, that's a gotcha. Again, that's (I bet) what those Z switches are for.

BTW .. there's 2 d**n much religion on this board! There's the liberal religion, the MACRO religion, atheism religion, Bertrand Russell religion, C/C++ religion ... pls don't start with the JWasm religion too! It's a great prog, best in the world, all other progs should not even be called prog's by comparison; Oh great J, mother of all perfection ... :biggrin:
Title: Re: Make procedure
Post by: jj2007 on May 29, 2015, 06:49:12 AM
Quote from: rrr314159 on May 29, 2015, 04:15:40 AMpls don't start with the JWasm religion too! It's a great prog, best in the world, all other progs should not even be called prog's by comparison; Oh great J, mother of all perfection ... :biggrin:

It's difficult to ignore it. While ML 6.14 is supplied with Masm32, it is too outdated for serious use. Higher versions are difficult to find and/or to install, and then there is always the license issue.

Today I found a new incompatibility between ML and J, in my ternary operator function macro. The fix will be online soon. It has become much better over time, but I still need fixes for this kind of problem. Nowadays J has become easier to use than ML, but still, I make sure that all MB macros must work with ML 6.15 ... 10 and JWasm.