News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Using a data label to map to mutliple strings

Started by CaptainPanda, June 21, 2018, 12:52:42 AM

Previous topic - Next topic

CaptainPanda

Hi all,

First post here, I've only just got started with MASM32 so excuse this if this is a real newbie question

Basically I have an .inc file that basically defines one label with two data initialisers (in the .code section because it was the only way to make it work):


.code
room1:
db "room1", 0
db "this is room 1", 0


My intent is to be able to pass the label as pointer to a section of predefined format to give data about a room. My problem seems to be that trying to access the second string there is that it crashes before it gets to it.

This is the code that I am using to try get the description there:


GetRoomDescription proc rptr:DWORD
mov edi, rptr

SkipName:
cmp edi, 0
je SkippedName
inc edi
jmp SkipName

SkippedName:
                inc    edi
mov eax, edi

ret

GetRoomDescription endp


The idea is that the start of the code goes to the first data and reads to the null terminator, then move the address into eax and return.

It crashes at the very start of the function.

Here is how I am calling it in the main function:


start:
    invoke GetLocOfRoom, offset roomToFind
    test    eax, eax
    je      SkipPrint
PrintRoom:
    push    eax
    WriteStringRegNL eax
    pop     eax
    push    eax
    invoke  GetRoomDescription, eax
    WriteStringRegNL eax
    pop eax


The first WriteString prints out the last the room name perfectly fine, if I add a WriteString to the start of the description function it reads as far as "room" but then crashes after that.

I am truly stumped and since I only started using MASM since yesterday, I'm really stuck

hutch--

Looking at some of your procedure names, this looks like Kip Irvine book code.

CaptainPanda

Quote from: hutch-- on June 21, 2018, 01:35:35 AM
Looking at some of your procedure names, this looks like Kip Irvine book code.

All my own code, just going with the docs and my own brain power but my brain power appears to have run out lol

Any idea what I am doing wrong?

zedd151

First, welcome to the forum!   :t

Quote from: CaptainPanda

All my own code, just going with the docs and my own brain power but my brain power appears to have run out lol

Any idea what I am doing wrong?

Post your full source so that we can assemble it to see what is happening with it. Plus just in case there are other errors in your code someone can better assist you when the full source is available.  :idea:

CaptainPanda

Quote from: zedd151 on June 21, 2018, 03:58:16 AM
First, welcome to the forum!   :t

Quote from: CaptainPanda

All my own code, just going with the docs and my own brain power but my brain power appears to have run out lol

Any idea what I am doing wrong?

Post your full source so that we can assemble it to see what is happening with it. Plus just in case there are other errors in your code someone can better assist you when the full source is available.  :idea:

Ah yes, forgot I'm not asking a question for a high level language, oops lol

Compiled with:

ml /c /coff /Zd zork.asm
Link /subsystem:console zork.obj
.\zork.exe


Here it is:

zork.asm

.486
.model flat, stdcall
option casemap :none

include rooms.asm

SplitInputToArr         PROTO
StripInputStr           PROTO

.data
    prompt          db "> ", 0
    lookStr         db "look", 0
    space           db " ", 0
    roomToFind      db "room1", 0

.data?
    input           db 80 dup(?)
    strippedInput   db 80 dup(?)
    verb            db 16 dup(?)
    noun            db 64 dup(?)

.code
start:
    invoke GetLocOfRoom, offset roomToFind
    test    eax, eax
    je      SkipPrint
PrintRoom:
    push    eax
    WriteStringRegNL eax
    pop     eax
    push    eax
    invoke  GetRoomDescription, eax
    WriteStringRegNL eax
    pop eax
SkipPrint:
    ;WriteString prompt
    ;ReadString input, 80
    ;invoke StripInputStr
    ;invoke SplitInputToArr
    ;WriteStringNL verb
    ;WriteStringNL noun
    invoke ExitProcess, 0

; -------------------------------
SplitInputToArr proc
        xor     eax, eax
        xor     ebx, ebx
        mov     ecx, offset strippedInput
        mov     edi, offset verb
        mov     esi, offset noun

    SplitArrGetVerb:
        cmp     eax, 15
        jz      SplitArrGetVerbTransistToNoun

        cmp     byte ptr [ecx], 32
        jz      SplitArrGetVerbTransistToNoun

        mov     edx, [ecx]
        mov     [edi], edx
        inc     ecx
        inc     edi
        inc     ax
        jmp     SplitArrGetVerb

    SplitArrGetVerbTransistToNoun:
        mov     al, 0
        mov     [edi], al
        inc     ecx
        jmp     SplitArrGetNoun
   
    SplitArrGetNoun:
        test    ecx, ecx
        jz      SplitArrBeforeEnd1

        cmp     ebx, 63
        jz      SplitArrBeforeEnd2

        mov     al, [ecx]
        mov     [esi], al
        inc     bx
        inc     ecx
        inc     esi
        jmp     SplitArrGetNoun
       
    SplitArrBeforeEnd1:
        mov al, 0
        mov [esi], al
        jmp SplitArrEnd

    SplitArrBeforeEnd2:
        mov al, [ecx]
        mov [esi], al
        jmp SplitArrEnd
   
    SplitArrEnd:
        xor     eax, eax

        ret
SplitInputToArr endp
; -------------------------------

StripInputStr proc

    local temp[80]: byte

        xor     eax, eax
        mov     ebx, offset strippedInput
        mov     ecx, offset input

    StripUntilFirstLetter:
        cmp     byte ptr [ecx], 32
        je      StripUntilFirstLetter1
        jmp     StripInnerSpaces
    StripUntilFirstLetter1:
        inc     ecx
        jmp     StripUntilFirstLetter

    StripInnerSpaces:
        cmp     byte ptr [ecx], 0
        je      StripRightSpace
        cmp     byte ptr [ecx], 32
        je      FoundSpace
        xor     eax, eax
        mov     edx, [ecx]
        mov     [ebx], edx
        inc     ecx
        inc     ebx
        jmp     StripInnerSpaces

    FoundSpace:
        inc     eax
        cmp     eax, 1
        jg      IgnoreSpace
        mov     edx, [ecx]
        mov     [ebx], edx
        inc     ecx
        inc     ebx
        jmp     StripInnerSpaces

    IgnoreSpace:
        inc     ecx
        jmp     StripInnerSpaces

    StripRightSpace:
        cmp     byte ptr [ebx], 32
        je      MoveBackSpace
        inc     ebx
        jmp     StripEnd

    MoveBackSpace:
        dec     ebx
        jmp StripRightSpace

    StripEnd:
        mov     edx, 0
        mov     [ebx], edx
        xor     eax, eax

        ret
StripInputStr endp
end start


rooms.asm

include rooms.inc

GetLocOfRoom PROTO :DWORD
GetRoomDescription PROTO :DWORD
TestStrings PROTO :DWORD, :DWORD

.data
newline     db 13, 10, 0
room1name db "room1", 0
passed db "passed", 0
;failed db "failed", 0

.data?
val db 8 dup(?)

.code
GetLocOfRoom proc r:DWORD

invoke TestStrings, r, offset room1name
test eax, eax
je room1Pass
jmp GetLocFail

room1Pass:
mov eax, room1
jmp GetLocEnd

GetLocFail:
mov eax, 0
jmp GetLocEnd

GetLocEnd:
ret

GetLocOfRoom endp

GetRoomDescription proc rptr:DWORD
mov edi, rptr

SkipName:
cmp edi, 0
je SkippedName
inc edi
jmp SkipName

SkippedName:
mov eax, edi

ret

GetRoomDescription endp

TestStrings proc s1: DWORD, s2: DWORD
mov eax, sizeof s1
mov ebx, sizeof s2
cmp eax, ebx
jne TestStringsFail
mov edi, s1
mov esi, s2
mov ebx, 0
mov ecx, sizeof s1

TestLetter:
cmp ebx, ecx
je TestStringsPass
mov al, [edi + ebx]
cmp al, [esi + ebx]
jne TestStringsFail
inc ebx
jmp TestLetter

TestStringsPass:
xor eax, eax
jmp TestStringsEnd

TestStringsFail:
mov eax, 1
jmp TestStringsEnd

TestStringsEnd:
ret

TestStrings endp


rooms.inc

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib

WriteStringReg MACRO reg
    invoke StdOut, reg
ENDM

WriteString MACRO s
    invoke StdOut, offset s
ENDM

WriteStringRegNL MACRO reg
    invoke StdOut, reg
    invoke StdOut, offset newline
ENDM

WriteStringNL MACRO s
    invoke StdOut, offset s
    invoke StdOut, offset newline
ENDM

ReadString MACRO s, len
    invoke StdIn, offset s, len
ENDM

.code
room1:
db "room1", 0
db "this is room 1", 0

zedd151

Yup, it hangs and crashes after displaying 'Room1'.

I didn't look into it with a debugger, but my best guess is that since esi, edi, and ebx are not getting preserved one of those is the culprit.
I am now going to debug it with xdbg to see whats really happening.

jj2007

eax is zero at this point:
    WriteStringRegNL eax

Check carefully what this code is doing:
GetRoomDescription proc rptr:DWORD
mov edi, rptr

SkipName:
cmp edi, 0
je SkippedName
inc edi
jmp SkipName

SkippedName:
mov eax, edi
.if !eax
mov eax, Chr$("ERROR")   ; to avoid the crash
.endif
ret

GetRoomDescription endp


Did you mean cmp byte ptr [edi], 0?

zedd151

Quote from: jj2007 on June 21, 2018, 05:18:07 AM
eax is zero at this point:
    WriteStringRegNL eax

jj's right.

something not right here. I see your desperate attempts to keep a value in eax:


PrintRoom:
    push    eax                             ;<-------  trying to prevent eax getting overwritten? offset of string "room1" now in eax
    WriteStringRegNL eax
    pop     eax                              ;<------- eax = 00000000 here

    push    eax                             ;<-------  trying to prevent eax getting overwritten? push eax (zero at this point)
    invoke  GetRoomDescription, eax
    WriteStringRegNL eax
    pop eax


study the code a little better. api's generally put a return value in eax. If you need to save that value, store it in a variable, or local variable. Then put it back into eax when needed.


yup. Getting access violation trying to use 00000000 as an address.

from olly:


0040109E  |. 50             PUSH EAX                                 ; /Arg1 ---eax contains address of string 'room1' here

0040109F  |. E8 D8000000    CALL zork.0040117C
004010A4  |. 68 00304000    PUSH zork.00403000
004010A9  |. E8 CE000000    CALL zork.0040117C
004010AE  |. 58             POP EAX                                 ; eax contains 0


004010AF  |. 50             PUSH EAX
004010B0  |. 50             PUSH EAX
004010B1  |. E8 87FFFFFF    CALL zork.0040103D





jj2007

No, it's not the stack, it's the inc edi until edi==0.

zedd151

Quote from: jj2007 on June 21, 2018, 06:20:17 AM
No, it's not the stack, it's the inc edi until edi==0.

OOps you're right just looked at it again in olly.  :P

I was watching the stack variable get changed, and didn't look at the program flow.  :icon_redface:

At any rate there is probably more than a dozen ways of doing this little piece of code. Seems a little long and drawn out.
But since he's learning, a good exercise none the less.

CaptainPanda

Quote from: jj2007 on June 21, 2018, 05:18:07 AM
eax is zero at this point:
    WriteStringRegNL eax

Check carefully what this code is doing:
GetRoomDescription proc rptr:DWORD
mov edi, rptr

SkipName:
cmp edi, 0
je SkippedName
inc edi
jmp SkipName

SkippedName:
mov eax, edi
.if !eax
mov eax, Chr$("ERROR")   ; to avoid the crash
.endif
ret

GetRoomDescription endp


Did you mean cmp byte ptr [edi], 0?

That seemed to fix it. Can I ask what "byte ptr []" actually does? Is it some form of indirection?

jj2007

Quote from: CaptainPanda on June 21, 2018, 07:06:37 AMCan I ask what "byte ptr []" actually does? Is it some form of indirection?

It compares the content of the memory pointed to by edi to zero. Your code just checked whether the pointer itself was zero... and that is not really what you wanted 8)

CaptainPanda

Quote from: jj2007 on June 21, 2018, 07:36:01 AM
Quote from: CaptainPanda on June 21, 2018, 07:06:37 AMCan I ask what "byte ptr []" actually does? Is it some form of indirection?

It compares the content of the memory pointed to by edi to zero. Your code just checked whether the pointer itself was zero... and that is not really what you wanted 8)

Ah right so I was essentially checking the memory address and not the value, that makes sense now, silly me.

Thanks for the help everyone, just learned of OllyDb from this so I feel I'll be better equipped come next problem.