I've likely made another beginners mistake here...
It appears to work correctly in a stand-alone .exe, but when I moved the code to a DLL loaded during Windows boot, it generates a memory access error 0x00000000 (can't remember if it was read or write).
num db "SomeString",0,0,0,0,0,0
...
pushad ; required - Windows crashes without this
; my code in here...
cld
mov ecx,1h
mov esi,offset num
mov edi,0h
cmpsb
; my code in here...
popad ; required - Windows crashes without this
What I wanted to do was check the first byte for a null value. In the code it contains an 8 byte string, null terminated, but padded with sufficient nulls to extend the total length to 16 bytes, including null terminator.
Is there anything obvious here that I'm missing that would create a memory access violation?
I do wonder if I should use 'byte ptr' instead of 'offset', but I can't see how that would prevent a memory access violation, especially as 'offset' works in a stand-alone .exe, and neither result in reading beyond the end of the string, or otherwise beyond the end of the data. Very bizarre. :eek
Best regards,
Astro.
Hi,
You are loading ESI with the offset to your strong.
You load EDI with zero. CMPSB will then read from
your string and the memory at zero to compare them.
That causes the memory access error.
You probably want to put zero in AL, The offset in
EDI and use SCASB to scan for a zero.
HTH,
Steve
:eek :eek :eek :eek
That makes sense - it is expecting a memory address in esi/edi not a value.
Thanks!
Best regards,
Astro.
also, if you are going to cmpsb a single byte, ecx need not hold the quantity
ecx needs to be set to a length if the rep prefix is used
hang in there, Astro :U
try this code....
xor eax,eax
mov ecx,eax
mov edi,offset num
repnz scasb
dec edi
neg ecx
afterwards, edi will point to the first 0
ecx will be the string length
hint - one of the few cases where ecx=0 means 4,294,967,296, or 100000000h
it makes the scas comparison, then decrements the ecx register, so after the first byte, ecx=FFFFFFFFh
Ahh - I thought ecx was decremented by cmpsb not rep.
Quotehang in there
Sure will!
Thanks for the code snippet! :thumbu
I see you put the address of num in edi, not esi? Is it not addressed edi:esi ?????
EDIT:
QuoteAE SCASB Compare AL with byte at ES:(E)DI and set status flags
OK - when is it esi:edi and edi:esi? Is there a rule or is it just how the instruction is put together at the time?
mov edi,offset num
xor eax,eax
cmpsb ; compare al with dl
jz SomeLabel ; jmp if byte NULL
Best regards,
Astro.
well - it isn't "esi:edi" or "edi:esi" - it is esi and edi - lol
when you put a ":" between registers, it implies they are paired to hold a single large value
sometimes. you may also see a segment register paired with a register - es:[di], for example
esi is the source index, edi is the destination index
some string instructions (like scas) require only one index register
lods - esi
stos - edi
scas - edi
cmps - esi and edi
movs - esi and edi
Quotecmpsb ; compare al with dl
that should read cmpsb ; compare al with [edi]
OK...
If I have:
MyString db "abcd",0
is it loaded into EDI as:
d|c|b|a
-------- edi
---- di
-- dl
?
Best regards,
Astro.
first, DL is the lower 8 bits of the EDX register - not EDI
only EAX, EBX, ECX, and EDX are split registers
but, yes, if you were to "mov edi,dword ptr MyString", the ascii "d" would be the high 8 bits of edi
notice i used "dword ptr" as a size override
that is because the data was defined as bytes and we are moving it into a dword register
the lower case letter 'a' is 97, or 61h, so edi would be 64636261h
this is not a normal use of edi, however
usually, we would put the offset of MyString into the edi register with "mov edi,offset MyString"
in that case, it is a 32-bit address that is assigned by the assembler
as assembler programmers, we are not generally too concerned with the exact value of the addresses
btw Astro - you have a great nic for avatars - lol
i found a couple you might like
hehe - thanks! :thumbu
I see - it is either EDI or DI.
Hmm - so if I got this right:
mov edi,dword ptr var - moves the CONTENTS of var into EDI
whilst:
mov edi,offset var - moves the ADDRESS of var into EDI
?
(Off-topic slightly)...so following on from that, what is the effect of:
mov eax,dword ptr [SomePointer]
if SomePointer was a DWORD pointing to an arbitrary block of memory for example?
Would it be:
0x00000000: 0x45 = SomePointer
0x00000001: 0xF4 = SomePointer
0x00000002: 0xAC = SomePointer
0x00000003: 0x12 = SomePointer
...
0x45F4AC12: 0x00 - first byte of the dword at 0x45F4AC12 pointed to by SomePointer?
If it was mov eax,offset [SomePointer] am I correct in thinking this would move the CONTENTS of 0x45F4AC12 into eax and not the ADDRESS of SomePointer (0x00000000)?
Best regards,
Astro.
that gets the value at the address named SomePointer
now, understand, that may be an address of some other data, stored as a dword pointer
we often pass pointers instead of data because you can send a pointer
to a structure that may contain many types and sizes of data
we often pass pointers to strings, as the string may be any length
i am working on a program now that has a circular buffer
the buffer is an array, 4 dwords per element
i use 2 pointers in the same structure to keep track of the "head" and "tail" of the buffer
in this case, as the buffer becomes full, i want to discard the oldest data
so, when i add an element to the array, i add 16 to the tail pointer
if the tail pointer is past the end of the array, i wrap it back to the beginning
if the new tail pointer is equal to the head pointer, i have to discard an element by bumping the head by 16
(that is because the condition of head=tail indicates empty buffer in this case)
that also means the updated tail pointer points to the location of the next entry
when i want to add something to the buffer, i grab the tail pointer and use it as a destination address
well - you get the idea - just trying to give you an example of uses of pointers
as you can see, this is much faster than moving all the elements in the array up by 16 bytes each time i add an element
Actually I'm confusing myself now.
Address of SomePointer = 0000
0000: 0005
0005: 2345
mov reg,SomePointer ; 0000
mov reg,[SomePointer] ; 0005
mov reg,word ptr SomePointer ; 0005
mov reg,word ptr [SomePointer] ; 2345 or 0005 ?
Best regards,
Astro.
what may be confusing you is the brackets
in your examples, nothing will change if you remove the brackets altogether
the only time you must use brackets is to use a register as an address like: "[ebx]" is different than "ebx"
another thing that may be confusing you is the use of "ptr"
there are two times you need to use "ptr"
1) to override the declared size of defined data
2) to specify the bit-width of an immediate value
1) if i have a data item defined as a dword "DwordVal dd 12345678h" (32-bit value)
let's say i want to load only the low-order 16-bits into ax - then "mov ax,word ptr DwordVal"
basically, this just avoids the assembler error "operand sizes must match"
another example:
i have a string "ByteString db 'some dang string' "
i want to grab 4 bytes at a time - "mov eax,dword ptr ByteString"
2) this is where you actually need to use the ptr to inform the assembler how wide an immediate value is
cmp [ebx],0
the assembler has no idea if you are refering to a byte, a word, or a dword
cmp dword ptr [ebx],0
now, the assembler knows you want to compare a dword to 0
Hmm....
If I had:
call HeapAlloc
mov SomeMemPtr,eax
and then:
mov SomeMemPtr,5h
this would trash SomeMemPtr and I'd lose the pointer to my memory.
I'd need to use:
mov byte ptr [SomeMemPtr],5h
so that 0x5 went into the first byte of where SomeMemPtr pointed, and not into SomeMemPtr itself.
Without the brackets, I'd trash the reference.
:eek :eek :eek
Actual example:
mov esi,offset [ptr_DEVICE_LIST_INFO+16]
I'll look at this tomorrow - 0300 here. I'm going to utterly confuse myself. :eek
Best regards,
Astro.
same same
the last example would also trash it
there are no labels to directly address allocated memory
you might do this:
mov ebx,SomeMemPtr
mov dword ptr [ebx],5
Quotemov esi,offset [ptr_DEVICE_LIST_INFO+16]
mov esi,offset ptr_DEVICE_LIST_INFO+16
esi will contain the address of 16 bytes above ptr_DEVICE_LIST_INFO
i think what you are wanting to do isn't allowed
that is to use a stored memory location as an address to access another memory location
you have to either get the address into a register or address it directly with a label - or a combination of the two
http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/Chapter_4/CH04-1.html
8 hrs diff - you must be in England :U
wifee is a Brit
push offset ptr_DEVICE_LIST_INFO+96 ; handle
and
push offset [ptr_DEVICE_LIST_INFO+96] ; handle
work.
Are the [] required at all (except as noted for registers)?
I'm trying to figure out just what goes where in memory.
I see the following happening:
SomeString (the variable itself) exists:
Address: Contents
0x00001234/5/6/7: 0x00452634 ; SomeString is at 0x1234 and points to the actual string at 0x00452634
0x00452634: 0x41 ; Capital letter 'A'
so:
push SomeString will push 0x00452634
push byte ptr SomeString will push 0x41
?
Quote8 hrs diff - you must be in England
I am indeed! :U That puts you somewhere along a very long West Coast! :lol
Best regards,
Astro.
no - the brackets are only needed if a regster holds the address
one thing that may help you a lot is to look at code that others have written and figure out what it does
that way, you will only see constructs that are valid
you are letting yourself be confused by storing a pointer in memory and attempting to use it to address data
it is best to just learn to address data, first - the fact that it is a pointer is just one type of meaning for that data
the \masm32\examples folder has many working programs
also, there are many working programs posted here in the forum
Quotepush SomeString will push 0x00452634
when you "push SomeString", the assembler generates "push dword ptr [00001234]"
the dword value at address 00001234 goes on the stack (00452634h)
i have to use brackets there because "push 00001234" will place the value 00001234 on the stack
the assembler does not allow you to write instructions using brackets and numbers
but, that is what a debugger or disassembler will see
Quotepush byte ptr SomeString will push 0x41
i have never tried to push a byte - lol - i don't think it will let you
(i could force it to happen, but it is best to always keep esp aligned by 4 in 32-bit programs)
i think you can only push words and dwords (unless it is a 64-bit operating system)
notice that "byte ptr" or "word ptr" only tells the assembler what bit-width to use
"ptr" does not otherwise change the behaviour of the instruction
again, you are trying to use a pointer, stored in memory, to address another memory location
this simply isn't allowed
"push word ptr SomeString" will push 2634h - the low order portion of the dword
if you want to get the 41 onto the stack...
mov ebx,SomeString
push word ptr [ebx]
or
mov ebx,SomeString
push dword ptr [ebx]
QuoteThat puts you somewhere along a very long West Coast!
i am near Phoenix Arizona, where the damn sun won't stop shining
at least it has dropped back below 110F (43.3C)
Quotei am near Phoenix Arizona, where the damn sun won't stop shining
at least it has dropped back below 110F (43.3C)
43.3°? How do you live out there??? I'm finding 26° (72F) and 60% rel. too much (but then no aircon so...).
Thanks for the avatar by the way! :bg
OK! I'm not sure where I picked up the brackets thing.
What is the deal with
offset then? is that
dword ptr in disguise? It makes sense.
Best regards,
Astro.
"offset" is used to get the address of a variable, as opposed to getting the variable, itself
you may also see "addr" - i think that's the same as "offset"
"ptr" is a size override, as explained earlier
you never see the 2 used together, because when you want the address, you don't care about it's width
yes - most everyone here has air conditioning
i survive by being outside as little as possible from about 10:00 AM to about 6:00 PM
that makes a lot of us here "night owls" in the summer
the middle of the night is a nice time to go for a dip in the pool or something
if you have to go outside in the daytime - sunglasses - hat - keep the skin covered
also, try to stay in the shade whenever possible and drink lots of water
soon, we will get our monsoon rains then a bit of humiduty
after that passes, it will be nice out - temp in the 80's and 10% humidity
The ADDR operator is intended for use with INVOKE. Because the OFFSET operator specifies an address constant that is resolved at assembly time, it will not work for a local variable that is allocated from the stack at run time. The ADDR operator duplicates the action of the OFFSET operator, or generates code to pass the address of a local variable, as necessary.
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.data
globaldd dd 1234h
buffer db 20 dup(0)
.code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
myproc proc
LOCAL localdd:DWORD
mov localdd, 5678h
nop
invoke dw2hex, ADDR globaldd, ADDR buffer
nop
invoke dw2hex, OFFSET globaldd, ADDR buffer
nop
invoke dw2hex, ADDR localdd, ADDR buffer
nop
;error A2098: invalid operand for OFFSET
;invoke dw2hex, OFFSET localdd, ADDR buffer
ret
myproc endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
inkey "Press any key to exit..."
exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
00401000 55 push ebp
00401001 8BEC mov ebp,esp
00401003 83C4FC add esp,0FFFFFFFCh
00401006 C745FC78560000 mov dword ptr [ebp-4],5678h
0040100D 90 nop
0040100E 6804304000 push 403004h
00401013 6800304000 push 403000h
00401018 E877000000 call fn_00401094
0040101D 90 nop
0040101E 6804304000 push 403004h
00401023 6800304000 push 403000h
00401028 E867000000 call fn_00401094
0040102D 90 nop
0040102E 6804304000 push 403004h
00401033 8D45FC lea eax,[ebp-4]
00401036 50 push eax
00401037 E858000000 call fn_00401094
0040103C 90 nop
0040103D C9 leave
0040103E C3 ret
thanks for straightening me out Michael
i had seen them used in what appeared to be interchangable fashion
so, ADDR will generate lea instructions ?
i see in the last example that it loads the lea into eax
Quoteinvoke dw2hex, ADDR localdd, ADDR buffer
Quote0040102E 6804304000 push 403004h
00401033 8D45FC lea eax,[ebp-4]
00401036 50 push eax
00401037 E858000000 call fn_00401094
what if i had another parm in eax ?
how does the assembler know which register to use ? - lol
as an example, what if i had parms in eax, ecx, and edx ?
what if...
INVOKE WriteFile,
eax,
edx,
ecx,
ADDR localWriteCount,
NULL
Quote from: dedndave on August 20, 2009, 07:27:07 PM
what if i had another parm in eax ?
You'll get an error message- register overwrite...