News:

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

masm struct beginner

Started by Mantis, January 06, 2008, 08:34:17 PM

Previous topic - Next topic

Mantis

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

Vortex

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.

Mantis

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,

Mantis

anyone that could make small commented example would be very appreciated.... :))

BogdanOntanu

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.
Ambition is a lame excuse for the ones not brave enough to be lazy.
http://www.oby.ro

Tedd

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.
No snowflake in an avalanche feels responsible.

Mantis

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

Mantis

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.

Mantis

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.

Mirno

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

Mantis

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,

evlncrn8

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..

Mantis

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 )

GregL

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 you can use USES.

Tedd

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)

No snowflake in an avalanche feels responsible.