I have an array of two-byte integers, which I am populating with random 3 digit numbers, using ESI to walk through the array. I am getting an access violation when I attempt to access the 9th element of the array and store it in ESI.
ARRAYSIZE = 200
.data
list WORD ARRAYSIZE DUP(?)
fillArray PROC
push OFFSET list
mov esi, [esp] ;GET ADDRESS OF FIRST ELEMENT INTO ESI
mov ecx, request ;NUMBER OF ELEMENTS TO BE ADDED
ArrFill:
;calculate random 3-digit number, store in eax
dec ecx
mov [esi], eax ;THIS IS THE LINE THAT THROWS THE EXCEPTION
sub esi, 2
cmp ecx, 0
jnz ArrFill
Exception thrown: Access violation writing location 0x00405FFE (The value of ESI when thrown).
When I change the array to four-byte integers, I also get an access violation for trying to access the 5th element of the array at the same address.
push OFFSET list
mov esi, [esp] ;GET ADDRESS OF FIRST ELEMENT INTO ESI
Why not simply assign the offset to ESI with mov esi, OFFSET list
mov [esi], eax ;THIS IS THE LINE THAT THROWS THE EXCEPTION
Since the array contains words you can only write the contents of AX, not EAX! Use mov [esi], ax
sub esi, 2
To progress through the array you need to add to the pointer not subtract from it. Use add esi, 2
Hudspero
You are getting an access violation because you are trying to write past the array boundary.
Few things:
You don't seem to be initializing ecx. You should initialize this to the size of the array.
As you are cmp ecx,0 you should be decrementing ecx before the comparison
You should move the esiaddress adjustment after you ensure you won't write past the boundary. I would restructure the code to test ecx for zero and jump out if true, otherwise decrement esiand jump back to ArrFill
Related
I'm was working on some homework to print out an array as it's sorting some integers from an array. I have the code working fine, but decided to try using EAX instead of AL in my code and ran into errors. I can't figure out why that is. Is it possible to use EAX here at all?
; This program sorts an array of signed integers, using
; the Bubble sort algorithm. It invokes a procedure to
; print the elements of the array before, the bubble sort,
; once during each iteration of the loop, and once at the end.
INCLUDE Irvine32.inc
.data
myArray BYTE 5, 1, 4, 2, 8
;myArray DWORD 5, 1, 4, 2, 8
currentArray BYTE 'This is the value of array: ' ,0
startArray BYTE 'Starting array. ' ,0
finalArray BYTE 'Final array. ' ,0
space BYTE ' ',0 ; BYTE
.code
main PROC
MOV EAX,0 ; clearing registers, moving 0 into each, and initialize
MOV EBX,0 ; clearing registers, moving 0 into each, and initialize
MOV ECX,0 ; clearing registers, moving 0 into each, and initialize
MOV EDX,0 ; clearing registers, moving 0 into each, and initialize
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET startArray ; load EDX with address of variable
CALL writeString ; print string
POP EDX ; return edx to previous stack
MOV ECX, lengthOf myArray ; load ECX with # of elements of array
DEC ECX ; decrement count by 1
L1:
PUSH ECX ; save outer loop count
MOV ESI, OFFSET myArray ; point to first value
L2:
MOV AL,[ESI] ; get array value
CMP [ESI+1], AL ; compare a pair of values
JGE L3 ; if [esi] <= [edi], don't exch
XCHG AL, [ESI+1] ; exchange the pair
MOV [ESI], AL
CALL printArray ; call printArray function
CALL crlf
L3:
INC ESI ; increment esi to the next value
LOOP L2 ; inner loop
POP ECX ; retrieve outer loop count
LOOP L1 ; else repeat outer loop
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET finalArray ; load EDX with address of variable
CALL writeString ; print string
POP EDX ; return edx to previous stack
CALL printArray
L4 : ret
exit
main ENDP
printArray PROC uses ESI ECX
;myArray loop
MOV ESI, OFFSET myArray ; address of myArray
MOV ECX, LENGTHOF myArray ; loop counter (5 values within array)
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET currentArray ; load EDX with address of variable
CALL writeString ; print string
POP EDX ; return edx to previous stack
L5 :
MOV AL, [ESI] ; add an integer into eax from array
CALL writeInt
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET space
CALL writeString
POP EDX ; restores the original edx register value
ADD ESI, TYPE myArray ; point to next integer
LOOP L5 ; repeat until ECX = 0
CALL crlf
RET
printArray ENDP
END main
END printArray
; output:
;Starting array. This is the value of array: +1 +5 +4 +2 +8
;This is the value of array: +1 +4 +5 +2 +8
;This is the value of array: +1 +4 +2 +5 +8
;This is the value of array: +1 +2 +4 +5 +8
;Final array. This is the value of array: +1 +2 +4 +5 +8
As you can see the output sorts the array just fine from least to greatest. I was trying to see if I could move AL into EAX, but that gave me a bunch of errors. Is there a work around for this so I can use a 32 bit register and get the same output?
Using EAX is definitely possible, in fact you already are. You asked "I was trying to see if I could move AL into EAX, but that gave me a bunch of errors." Think about what that means. EAX is the extended AX register, and AL is the lower partition of AX. Take a look at this diagram:image of EAX register
. As you can see, moving AL into EAX using perhaps the MOVZX instruction would simply put the value in AL into EAX and fill zeroes in from right to left. You'd be moving AL into AL, and setting the rest of EAX to 0. You could actually move everything into EAX and run the program just the same and there'd be no difference because it's using the same part of memory.
Also, why are you pushing and popping EAX so much? The only reason to push/pop things from the runtime stack is to recover them later, but you never do that, so you can just let whatever is in EAX at the time just die.
If you still want to do an 8-bit store, you need to use an 8-bit register. (AL is an 8-bit register. IDK why you mention 16 in the title).
x86 has widening loads (movzx and movsx), but integer stores from a register operand always take a register the same width as the memory operand. i.e. the way to store the low byte of EAX is with mov [esi], al.
In printArray, you should use movzx eax, byte ptr [esi] to zero-extend into EAX. (Or movsx to sign-extend, if you want to treat your numbers as int8_t instead of uint8_t.) This avoids needing the upper 24 bits of EAX to be zeroed.
BTW, your code has a lot of unnecessary instructions. e.g.
MOV EAX,0 ; clearing registers, moving 0 into each, and initialize
totally pointless. You don't need to "init" or "declare" a register before using it for the first time, if your first usage is write-only. What you do with EDX is amusing:
MOV EDX,0 ; clearing registers, moving 0 into each, and initialize
PUSH EDX ; preserves the original edx register value for future writeString call
MOV EDX, OFFSET startArray ; load EDX with address of variable
CALL writeString ; print string
POP EDX ; return edx to previous stack
"Caller-saved" registers only have to be saved if you actually want the old value. I prefer the terms "call-preserved" and "call-clobbered". If writeString destroys its input register, then EDX holds an unknown value after the function returns, but that's fine. You didn't need the value anyway. (Actually I think Irvine32 functions at most destroy EAX.)
In this case, the previous instruction only zeroed the register (inefficiently). That whole block could be:
MOV EDX, OFFSET startArray ; load EDX with address of variable
CALL writeString ; print string
xor edx,edx ; edx = 0
Actually you should omit the xor-zeroing too, because you don't need it to be zeroed. You're not using it as counter in a loop or anything, all the other uses are write-only.
Also note that XCHG with memory has an implicit lock prefix, so it does the read-modify-write atomically (making it much slower than separate mov instructions to load and store).
You could load a pair of bytes using movzx eax, word ptr [esi] and use a branch to decide whether to rol ax, 8 to swap them or not. But store-forwarding stalls from byte stores forwarding to word loads isn't great either.
Anyway, this is getting way off topic from the title question, and this isn't codereview.SE.
I'm trying to print the contents of an array by using assembly language as below.
I could compile the code, but I could not run it.
How should I fix the code to print the contents of an array?
TITLE arrayFill_example (arrayFill_ex.asm)
INCLUDE Irvine32.inc
.data
count = 5
array DWORD count DUP(?)
arraySize = ($ - array) / 4
.code
; saves the general-purpose registers, retrieves the parameters, and fills the array
ArrayFill PROC
push ebp
mov ebp,esp
pushad ; save registers
mov esi,[ebp+12] ; offset of array
mov ecx,[ebp+8] ; array length
cmp ecx,0 ; ECX == 0?
je L2 ; yes: skip over loop
L1:
mov eax,10000h ; get random 0-FFFFh
call RandomRange ; from the link library
mov [esi],ax ; insert value in array
add esi,TYPE WORD ; move to next element
loop L1
L2: popad ; restore registers
pop ebp
ret 8 ; clean up the stack
ArrayFill ENDP
main PROC
push OFFSET array ; passed by reference
push count ; passed by value
call ArrayFill
; for showing array contents
mov eax, 0
mov esi, array
mov ecx, arraySize
L1:
mov eax, array[esi * TYPE array]
call WriteInt
call Crlf
add esi, 4
loop L1
exit
main ENDP
END main
Specifically this part is not working for me...
; for showing array contents
mov eax, 0
mov esi, array
mov ecx, arraySize
L1:
mov eax, array[esi * TYPE array]
call WriteInt
call Crlf
add esi, 4
loop L1
Problem 1
array DWORD count DUP(?)
With this definition the array contains dwords. But your program just fills the array with words using:
mov [esi],ax ; insert value in array
add esi,TYPE WORD ; move to next element
Better write:
mov [esi], eax ; insert value in array
add esi, 4 ; move to next element
Problem 2
mov esi, array
...
mov eax, array[esi * TYPE array]
These lines are redundantly referring to the array. That's adding a pointer to a pointer, giving the wrong address! (Or actually, mov esi, array loaded the first element, not the address, because that's how MASM syntax works.)
mov esi, OFFSET array gives you the address in esi. From there, [esi] is the first element, array[esi] is similar to C array[ (intptr_t)array ] (but just a byte offset without scaling by the element size). The resulting address is unlikely to be valid.
Just use one or the other, indexing with small integers, or a pointer increment. Getting a pointer into a register is usually good, as in:
mov esi, OFFSET array
mov ecx, arraySize
L1:
mov eax, [esi]
call WriteInt
call Crlf
add esi, 4
loop L1
I am experiencing some difficulties with understanding of how I can calculate the offset to the row in two dimensional array. The offsets will be used by main later to access the rows for the assignments and quizzes.
Assuming that I have,
scores DWORD 80,80,100, ; midterms, 2 scores
20,20,20,20,20,20,20,100, ; assignments, 7 scores
10,10,10,10,10,10,100 ; quizzes, 6 scores (lowest score dropped)
where "100" is a sentinel value. I understand that the offset is how many bytes away is the row from the start of array.
mov ecx, sentinelVal
mov edi, OFFSET scores
mov eax, sentinelVal
OffsetLoop:
repne scasd ; walk through the array until the target value is found.
jnz endLoop ; if the sentinel value is not found jump from the loop
; If the sentinel value if found
; edi is pointing to the location after the sentinel value
; I am not sure what I should do with the address of the array and edi
; to figure out the offset. Any help would be appreciated. Thanks!
loop OffsetLoop
endLoop:
edited:
I figured out what was my problem. My approach to calculate the offset was right, but it was the loop that caused the problem. It's not possible to simply set ecx to any arbitrary large numbers because scasd also uses ecx as a counter. By setting ecx to a large number, the instruction goes beyond the array boundary which triggers the exception.
mov ecx, LENGTHOF scores
OffsetLoop:
cld
repne scasd
jnz endLoop
mov ebx, edi
sub ebx, OFFSET scores
push ebx
inc ecx
loop OffsetLoop
endLoop:
Assuming your descriptions are correct in that edi is left pointing one beyond the sentinel word, you can simply do:
sub edi, OFFSET scores
to get the byte offset from the beginning of the table.
I'd be a little worried about this though:
mov ecx, sentinelVal
The ecx register is supposed to be a length limit and, while 100 may be a decent value, you should have a different symbolic name for it such as lenLimit.
I'm having some difficulty with my array accessing in MASM. I've got a very large array and a temp variable like so:
.data
array DWORD 65000 DUP (0)
temp DWORD 0
In my main, I've got this to fill it:
mov esi, offset array
mov edi, 0
mov ecx, 0
fill:
mov [esi], ecx
add esi, 4
inc ecx
cmp ecx, 65000
jl fill
mov esi, offset array ;reset the array location to the start
After, I want to access the array with this loop:
mark:
mov temp, 4 ;get another 4 to temp to move along the array
add esi, temp ;add temp to esi to keep moving
mov edx, [esi] ;access the current value
cmp esi, 20 ;just trying to get first few elements
jmp mark
exit
main ENDP
END main
I always have an access violation error, with the break at the line where I try to access the current value. This occurs on the very first loop as well. Any idea why this is happening? Thanks!
Your code will work to an extent, however:
mark:
mov temp, 4
add esi, temp ;Incrementing before first loop means you miss the first stored value
mov edx, [esi]
cmp esi, 20 ;ESI is the address your are accessing, not a count
jmp mark ;This loop will be infinite
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
x86 convert to lower case assembly
This program is to convert a 2d char array into lower case
Quickie Edit: I'm using Visual Studio 2010
int b_search (char list[100][20], int count, char* token)
{
__asm
{
mov eax, 0 ; zero out the result
mov esi, list ; move the list pointer to ESI
mov ebx, count ; move the count into EBX
mov edi, token ; move the token to search for into EDI
MOV ecx, 0
LOWERCASE_TOKEN: ;lowercase the token
OR [edi], 20h
INC ecx
CMP [edi+ecx],0
JNZ LOWERCASE_TOKEN
MOV ecx, 0
At my OR instruction, where I'm trying to change the register that contains the address to token into all lower case, I keep getting unhandled exception...access violation, and without the brackets nothing gets lowercased. Later in my code I have
LOWERCASE_ARRAY: ;for(edi = 0, edi<ebx; edi++), loops through each name
CMP ecx, ebx
JGE COMPARE
INC ecx ;ecx++
MOV edx, 0; ;edx = 0
LOWERCASE_STRING: ;while next char != 0, loop through each byte to convert to lower case
OR [esi+edx],20h ;change to lower case
INC edx
CMP [esi+edx],0 ;if [esi+edx] not zero, loop again
JNZ LOWERCASE_STRING
JMP LOWERCASE_ARRAY ;jump back to start case change of next name
and the OR instruction there seems to work perfectly so I don't know why the first won't work. Also, I am trying to convert several strings.
After I finish one string, any ideas how I would go about going to the next string (as in list[1][x], list[2][x], etc...) I tried adding 20 as in [esi+20*ecx+edi] but that doesn't work. Can I get advice on how to proceed?
One possibility:
If parameters of procedure b_search are stored as registers (register calling convention) then you override list pointer in your first asm line, because eax point to the list array:
mov eax, 0 ; zero out the result
Because:
mov esi, list ; move the list pointer to ESI
should be converted to:
mov esi, eax
Try to exchange first and second line to:
mov esi, list ; move the list pointer to ESI
mov eax, 0 ; zero out the result