The MASM Forum Archive 2004 to 2012

General Forums => The Workshop => Topic started by: Mantis on January 06, 2008, 08:34:17 PM

Title: masm struct beginner
Post by: Mantis on January 06, 2008, 08:34:17 PM
hi, i've only recently got into using masm/asm my question is with using structs... if i have the following struct:


nicks STRUCT
nickname db 100 dup(?)
addedby db 100 dup(?)
next dd ?
nicks EndS


now i'd like to create many of these, but without the use of an array, i'd like just to use next as a pointer to the newly created struct.. now this is all happening inside a dll so on each function call i'd like to create a new `nicks` can someone help...

thanks in advance
Title: Re: masm struct beginner
Post by: Vortex on January 06, 2008, 09:02:42 PM
Hi Mantis,

Welcome to the forum.

Not sure but maybe something like this would help you:

mov esi,buffer ; variable pointing the memory block stroring the first nicks entry
.
.
.
add esi,SIZEOF(nicks) ; jump to the next entry


Are you sure that you need to use the member named next? I assume that every record in your database has the same lenght.
Title: Re: masm struct beginner
Post by: Mantis on January 06, 2008, 09:10:23 PM
hi thanks for quick response...

basically, what i plan todo is a very quick check through all the structs to find a specific nick, if it exists then stop, now rather then a while loop through an array, i'd basically do something like


.while edi > 0
;do checks etc here, then move on...
;also exit while if found.

mov edi, ptr.next
.endw


ptr being set as edi, and next being the pointer of the next nicks record.

but what i'm not understanding is how to initialize a new struct in mem.

thanks,
Title: Re: masm struct beginner
Post by: Mantis on January 06, 2008, 11:39:21 PM
anyone that could make small commented example would be very appreciated.... :))
Title: Re: masm struct beginner
Post by: BogdanOntanu on January 07, 2008, 04:28:11 AM
It is basic and simple ... so we will not make your homework for you. Let us know what you have tried and where you encounter any problems and why... and then we might help.

The way I see it now nobody stops you from establishing the correct value of "next" link.

However your algorithm is basically wrong. As Vortex kindly showed you it is much faster to simply go to the next record by adding the record/structure size.

This holds true unless you do something much advanced or you have a homework requirement to use "next" or you are hiding some information or requirement from us.

There is nothing essentially wrong or good with linked lists or with fixed length records but their use and advantages or disadvantages depend enormously on the problem to be solved.
Title: Re: masm struct beginner
Post by: Tedd on January 07, 2008, 02:09:50 PM
What you need to do is learn how to allocate memory - so you can allocate a new 'nicks' struct each time..
Read up on "GlobalAlloc" (and "GlobalFree"). Allocate a block of size "SIZEOF nicks" and then store the returned pointer in the previous struct's 'next' pointer. Just remember to keep hold of the very first pointer (the start of the linked list) somewhere else (since there's no previous struct) :wink

That is the solution to what you asked. The other members' suggestions are that you consider allocating one large array with each 'element' as one nick struct, since its size is quite small (200 bytes). I would agree with them - it is definitely much faster and cleaner. But that solution is only really practical if you know the maximum in advance and it is fairly small (say, less 10000). Otherwise you could still mix the two ideas and extend to blocks of arrays, but then it starts getting complicated.
Title: Re: masm struct beginner
Post by: Mantis on January 07, 2008, 03:20:23 PM
Quote from: BogdanOntanu on January 07, 2008, 04:28:11 AM
It is basic and simple ... so we will not make your homework for you. Let us know what you have tried and where you encounter any problems and why... and then we might help.

The way I see it now nobody stops you from establishing the correct value of "next" link.

However your algorithm is basically wrong. As Vortex kindly showed you it is much faster to simply go to the next record by adding the record/structure size.

This holds true unless you do something much advanced or you have a homework requirement to use "next" or you are hiding some information or requirement from us.

There is nothing essentially wrong or good with linked lists or with fixed length records but their use and advantages or disadvantages depend enormously on the problem to be solved.


hi, because each block will not be allocated right after the first, so if i used the method posted, this would cause problems no?

Quote from: Tedd on January 07, 2008, 02:09:50 PM
What you need to do is learn how to allocate memory - so you can allocate a new 'nicks' struct each time..
Read up on "GlobalAlloc" (and "GlobalFree"). Allocate a block of size "SIZEOF nicks" and then store the returned pointer in the previous struct's 'next' pointer. Just remember to keep hold of the very first pointer (the start of the linked list) somewhere else (since there's no previous struct) :wink

That is the solution to what you asked. The other members' suggestions are that you consider allocating one large array with each 'element' as one nick struct, since its size is quite small (200 bytes). I would agree with them - it is definitely much faster and cleaner. But that solution is only really practical if you know the maximum in advance and it is fairly small (say, less 10000). Otherwise you could still mix the two ideas and extend to blocks of arrays, but then it starts getting complicated.


hi thanks very much Tedd, that is all i needed to know (GlobalAlloc), i was not sure if structs were to be initialized different

thanks again
Title: Re: masm struct beginner
Post by: Mantis on January 08, 2008, 07:53:55 PM
hi is it possible someone could verify my code?...



AddNickBan proc pNick:DWord, pReason:DWord, pBannedBy:DWord, pBanTime:DWord, pExp: DWord
invoke GlobalAlloc, GMEM_FIXED, sizeof TNickban
mov nickban, eax
mov edx, eax

assume edx:ptr TNickban

lea ebx, [edx].nickname
cld
mov esi, pNick
mov edi, ebx

mov ecx, sizeof pNick
rep movsb

mov eax, nickban
mov last, eax

.if first == 0
mov first, eax
.endif

assume edx:nothing

Ret
AddNickBan endp



first, last, nickban is placed under .data?


.data?
  first     dd     ?
  last     dd     ?
  nickban   dd   ?


TNickban is my struct

thanks in advance for any help.
Title: Re: masm struct beginner
Post by: Mantis on January 09, 2008, 02:41:07 PM
hi again, i have been getting a bit furthur, and now i jus cant find what i am doing wrong, is it possible someone can please help....

my code:


.386

.model flat, stdcall

option casemap:none

Include windows.inc
Include user32.inc
Include kernel32.inc

IncludeLib user32.lib
IncludeLib kernel32.lib


Include banlib.inc

.data?

TNickban STRUCT
nickname db 100 dup(?)
reason db 255 dup(?)
bannedby db 100 dup(?)
banattime dd ?
expires dd ?
next dd ?
TNickban EndS

;Pointers to First, Last and Prev.

pFirstRecord dd ?
pLastRecord dd ?
pPrevRecord dd ?

mov pFirstRecord, 0
mov pLastRecord, 0
mov pPrevRecord, 0

.code

DllEntry proc hInstance:HINSTANCE, reason:DWORD, reserved1:DWORD
.if reason == DLL_PROCESS_ATTACH
.elseif reason == DLL_PROCESS_DETACH
.elseif reason == DLL_THREAD_ATTACH
.else
.endif
mov  eax,TRUE
ret
DllEntry Endp


;add a nickname to ban list :)
AddNickBan proc pNick:DWord, pReason:DWord, pBannedBy:DWord, pBanTime:DWord, pExp: DWord
; move old nickban to prev :)
mov eax, pLastRecord
mov pPrevRecord, eax

;allocate mem for a new nickban :)
invoke GlobalAlloc, GPTR, sizeof TNickban
mov edx, eax

;assume edx is a nickban
assume edx:ptr TNickban

lea ebx, [edx].nickname
ByteCopy pNick, ebx, 100

lea ebx, [edx].reason;
ByteCopy pReason, ebx, 255
   
lea ebx, [edx].bannedby;
ByteCopy pBannedBy, ebx, 100        
           
;mov esi, pBanTime
;mov [edx].banattime, esi
;mov esi, pExp
;mov [edx].expires, esi

;our last item added is @ eax
mov eax, edx
mov pLastRecord, eax

.if pFirstRecord == 0
mov pFirstRecord, eax
.else
mov edx, pPrevRecord
mov [edx].next, eax
.endif

assume edx:nothing

return 1
AddNickBan endp

GetBan proc pBanID: DWord
; edx is our first nickban
mov edx, pFirstRecord

;lets assume edx is a pointer to a nickban (which it is..)
assume edx:ptr TNickban

;now while edx ...
.while edx
;load effective mem from nickname to eax.
lea eax, [edx].nickname
;check it is correct, just for a test :)
invoke MessageBox, 0, eax, eax, MB_OK

;now lets move the next pointer to eax
mov edx, [edx].next
.endw

assume edx:nothing

return 1
GetBan EndP

End DllEntry


my macros used:



; inline memory copy macro
ByteCopy MACRO lpSource, lpDest, len
mov esi, lpSource
    mov edi, lpDest
    mov ecx, len
    rep movsb
ENDM
     
;replacement for mov eax, ... and ret.         
return MACRO arg
mov eax, arg
    ret
ENDM



i know the code is not the best nor is it the 'quickest' but im still new to asm. anyways....


the getban is where i am having the problem... it will messagebox first nickname, which is great, but then it moves on showing a bit garbage, and then an exception..... thanks in advance for any help.
Title: Re: masm struct beginner
Post by: Mirno on January 09, 2008, 05:37:55 PM
eax, ecx, and edx are not preserved by function calls. So before your call to messagebox edx is what you expect after it is purely down to whether microsoft decided to use edx or not.

On a similar note, you aren't preserving ebx, edi and esi which you use in your function...

Mirno
Title: Re: masm struct beginner
Post by: Mantis on January 09, 2008, 06:12:05 PM
Quote from: Mirno on January 09, 2008, 05:37:55 PM
eax, ecx, and edx are not preserved by function calls. So before your call to messagebox edx is what you expect after it is purely down to whether microsoft decided to use edx or not.

On a similar note, you aren't preserving ebx, edi and esi which you use in your function...

Mirno

hmm i am not quite sure i understand what u mean..however uptil the messagebox everything works, but after the first messagebox then it causes error, thanks for reply tho, if you dont mind to explain a little more? or even if you could point me to right page in masm32 manual

thanks,
Title: Re: masm struct beginner
Post by: evlncrn8 on January 09, 2008, 06:14:55 PM
what he means is that most of the windows api calls do not preserve the ebx, ecx, edx registers
so you must preserve them, do the api call, and then restore them...

also for callbacks you must preserve esi, ebx, and edi (i think) within the callback proc and restore
them before returning from the callback proc...

you can easily see what registers are changed by debugging your app with ollydbg or whatever..
Title: Re: masm struct beginner
Post by: Mantis on January 09, 2008, 08:07:11 PM
thank you Mirno and evlnrcn8

i almost understood what you told me, and asked also a friend to explain and now i understand thanks


GetBan proc pBanID: DWord
LOCAL pEdx: DWord
; edx is our first nickban
mov edx, pFirstRecord

;lets assume edx is a pointer to a nickban (which it is..)
assume edx:ptr TNickban

;now while edx ...
.while edx
mov pEdx , edx
;load effective mem from nickname to eax.
lea eax, [edx].nickname
;check it is correct, just for a test :)
invoke MessageBox, 0, eax, eax, MB_OK
mov edx, pEdx

;now lets move the next pointer to eax
mov edx, [edx].next
.endw

assume edx:nothing

return 1
GetBan EndP


so yes this has solved all my problems, thank you very much, very helpful forum. ( i have only properly been coding in asm for 2 days now )
Title: Re: masm struct beginner
Post by: GregL on January 10, 2008, 12:54:03 AM
Quotealso for callbacks you must preserve esi, ebx, and edi (i think) within the callback proc and restore
them before returning from the callback proc...

Not just for callbacks, they should be preserved in any procedure in Windows programs. See the masm32 asmintro.hlp file, 'Register Preservation Convention'.

If you are using PROC (http://msdn2.microsoft.com/en-us/library/01d2az3t.aspx) you can use USES.
Title: Re: masm struct beginner
Post by: Tedd on January 10, 2008, 12:55:25 PM
The registers ecx and edx will be modified by (almost) any api function you call, so if you want to use their value again after the function call, you must save it. Registers ebx, edi and esi will (usually) be preserved by functions you call, so there's no need to save their values - however, the same expectation is on you and you must save their previous values if you use them, and restore them before returning from your procedure.

I think you've got that anyway, just clearing up :wink

A better way to save the values, instead of creating a new variable just for that purpose, is to use the stack - push/pop:

    push edx        ;save the value of edx
    ...do stuff.. call functions...
    pop edx        ;get back the value of edx (into edx)

Title: Re: masm struct beginner
Post by: Mantis on January 10, 2008, 06:38:01 PM
Quote from: Tedd on January 10, 2008, 12:55:25 PM
The registers ecx and edx will be modified by (almost) any api function you call, so if you want to use their value again after the function call, you must save it. Registers ebx, edi and esi will (usually) be preserved by functions you call, so there's no need to save their values - however, the same expectation is on you and you must save their previous values if you use them, and restore them before returning from your procedure.

I think you've got that anyway, just clearing up :wink

A better way to save the values, instead of creating a new variable just for that purpose, is to use the stack - push/pop:

    push edx        ;save the value of edx
    ...do stuff.. call functions...
    pop edx        ;get back the value of edx (into edx)



aha, great thanks everyone for help.

i have came to another problem whilst working on my dll, it is more todo with string comparison, now i have been told by a friend using repne scan is quicker, but for now the way i am doing i cant get to work lol, it is using a pointer from the struct to a passed pointer

i have not changed to push n pop for register, still local for now, as i had original wrote this proc, i know i have made not focused on speed atm, but to just get it working.



CheckBan proc pNick: DWord
LOCAL pEdx: DWord

mov edx, pFirstRecord ; set edx as our first record :)
assume edx:ptr TNickban ; assume it is a nickban

.while edx
mov pEdx , edx ; store edx in pedx for now :)

lea esi, [edx].nickname ;load nickname address into esi
mov edi, pNick ; pnick in edi
mov ecx, sizeof pNick ;length of pNick :)
repe cmpsb
jnz @exit

mov edx, pEdx
mov edx, [edx].next
.endw
mov eax, 0
jmp @quit
@exit:
mov eax, 1
@quit:
assume edx:nothing
ret
CheckBan endp

Title: Re: masm struct beginner
Post by: Tedd on January 10, 2008, 07:40:36 PM
Quote
i have been told by a friend using repne scan is quicker
It varies depending on the length of the string you're comparing, and the machine you're running on - and the difference isn't really something you need to worry about.


.while edx
    mov pEdx , edx ; store edx in pedx for now :)

    lea esi, [edx].nickname ;load nickname address into esi
    mov edi, pNick ; pnick in edi
    mov ecx, sizeof pNick ;length of pNick :)
    repe cmpsb
    jnz @exit

    mov edx, pEdx
    mov edx, [edx].next
.endw

Let's see..
* you're not calling any functions in there, so there's no need for saving edx :wink
* "lea esi,[edx].nickname" will give you a pointer to the start of the nickname - good
* "mov edi,pNick" assuming pNick is correct - fine
* "mov ecx,sizeof pNick" ...aaahhh. Not good. 'sizeof' returns the size of the given type - the type of pNick is dword - so you'll get 4 every time, no matter what string it happens to point to. To get the length of a string you need to count its characters (at run time; unless it happens to be a constant string literal, but this isn't.)
* "repe cmpsb" - yeah, but ecx is wrong, so you only ever compare up to the first 4 characters..

Since ecx is the maximum number of characters before rep gives up, you can just set it to "sizeof TNickban.nickname", so then it will compare up to the end of the nickname, but it would only get that far in the event that all characters match and nickname is maximum length. Otherwise, after rep stops, the value of ecx isn't much help, and neither is the status of the zero flag (since it will always be false - the reason 'rep' finished). So then you'll need to check whether the last bytes compared were zeroes (assuming you have zero-terminated strings), and if they were the strings match, otherwise they don't.
I would reconsider doing the comparison 'manually' byte-by-byte :wink
Title: Re: masm struct beginner
Post by: Mantis on January 10, 2008, 08:03:32 PM
thanks again tedd for reply, you are very helpful... but i do not quite understand how you mean ' doing the comparison 'manually' byte-by-byte '

thanks again :)