assembly - accessing array elements - arrays

I have an array that I am attempting to print.
I would like to print it out so I can see if it is correct.
It is currently printing the number 1 and stopping. Or, if I mess with the ECX differently it prints out a bunch of zeros and crashes.
Here is my program.
.data
array DWORD 10 DUP(5, 7, 6, 1, 4, 3, 9, 2, 10, 8)
my_size dd 10
sorted DWORD 0
first DWORD 0
second DWORD 0
.code
start:
main proc
cls
mov EBX, offset[array]
mov ECX, [my_size]
dec ECX
sub ESI, ESI
sub EDI, EDI
; print
mov EBX, offset aa
sub ECX, ECX
;mov ECX, my_size
mov ECX, 10
my_loop:
mov EAX, [EBX]
inc EBX
dec ECX
cmp ECX, 0
jle exit_loop
mov first, EAX
print chr$("printing array elements: ")
print str$(first)
loop my_loop
exit_loop:
ret
main endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end start

I hate to say it, but you're not "ready" to write a bubble sort. Either it's a completely insane homework assignment, or you haven't followed along with the class so far (possibly both).
Very first thing, I don't think you've defined your array correctly. As I read your code, you've got 100 dwords there - 10 copies of the 10 numbers you specify. You shouldn't need "DUP" in there.
I would print the unsorted array first, just to make sure you've got that part right. You appear to be using a couple of macros, there - they sure as heck aren't instructions. Just from the names, I would guess(!) that "print_chr$" prints a single character and "print_str$" prints a string (although you seem to be printing your string and the number 1). If you've got a "print_int$" in your macro set, I would guess(!) that's what you want. Since I'm not familiar with your macros, I could be wrong.
Although you've defined the array as "dword", you only compare a single byte in your sort routine. This probably works for the small numbers you're using, but it isn't really right.
The usual way to do a bubble sort is to set a "flag" (register or variable - this may be what "sorted" is for) to zero at the beginning of each run through the array, and set it to 1 every time you do a swap. When you've done a pass through your array and the flag is still zero - you haven't done a swap - then, and only then, your array is sorted. If you print the array after each pass, you'll see why it's called a "bubble" sort - the smallest/largest number "bubbles up" to its final position.
Your code to walk through a dword array (esi * 4) looks about right (outside of only comparing a byte), but your print routine only increments ebx by one each time through the loop. Either "add ebx, 4" or use "ebx * 4" (not both) to print dwords. Or perhaps your array is only supposed to be bytes?
Seriously, I'd start with something simpler - just print the array - and work up to adding the sort routine after you've got that working.
Hope it helps.
Best,
Frank

I see you've simplified the code. Good idea! I'm still not familiar with the macro you're using, "print_str$". That doesn't "look" to me like it prints a number. Have you got a "print_int$" or similar? If you can get it to print just the first number "5", that would be a good start.
Now... working through your loop, you just "inc ebx". That won't get you the next dword, it'll get you bytes 2, 3, and 4 from the first dword and the first byte from the second dword. Since you used "* 4" in the (removed) sort code, you probably want "[ebx * 4]" here. Either that, or add 4 to ebx each time through the loop. One or the other (but not both) should step through an array of dwords.
I suspect that the first step would be to select the "right" macro to print a number. It'll probably get easier from there(?). Courage! :)
Best,
Frank

Related

Issue properly comparing strings in intel assembly

My goal is to compare two strings. If they are equal continue the program. If not equal, branch somewhere else. If I'm not at the end of the string and so far everything is equal, loop over to next character.
I am using visual studio, inline intel asm.
The program is functioning, although, on its first run-through, it takes the NOTSAME branch and proceeds to end the program, even though the strings being compared are the same. It does not loop at all because of this, which means something is going wrong in the comparison.
I have tried debugging it and seemingly the registers hold the correct address. Incrementing/decrementing it seems to work, from my understanding, incrementing it just moves the pointer one byte forward, pointing towards the next character. I don't really have a clear idea of which part is going wrong, I just know it isn't getting compared in how I planned.
int main()
{
string arr[] = {"a","b","c","d","e" };
string a= "a";
__asm
{
lea esi, arr // load address into esi
lea edi, a
dec edi
LOOPING:
inc edi// ds:di->next character in string2
lodsb// load al with next char from string, lodsb increments si automatically.
cmp[edi], al//; compare characters
jne NOTSAME//; jump out of loop if they are not the same
cmp al, 0//; they are the same, but end of string ?
jne LOOPING//; no - so go round loop again
After some more debugging, it seems AL is not taking the correct byte from the string. Not sure why yet.
So for some reason, LEA stored the address 4 bytes before where the string starts. I am unsure why this is, but to fix it, I added 4 bytes to each register(pointers) and they both adjusted and now compare properly.
Changed the following
lea esi, a// load address into esi
lea edi,arr
add edi,4
add esi,4

How can I find the last 0 on an array in nasm?

I'm writing code to find the last 0 on an array.
Basically I need to move a new value on the "top" of each array, if it has only zeros it puts it at the end and if it finds other value it puts it on the last 0 (I'm treating my arrays as piles).
So far my subroutine works fine for the most part but sometimes it rewrites a value that I don't want (instead of getting the first value different from 0 it takes the next one). Here's the code I've been using to get the "top" of the array.
TOP:
xor ecx,ecx
xor ebx,ebx
TOP_FOR:
mov bx,word[eax+ecx*2] ;eax has the pointer of the array
cmp ecx,n ;n is the array's length
je END_TOP
inc ecx
cmp bx,0
je TOP_FOR
;here i get the direction of the first value different
END_TOP: ;from 0 but in my code i need the last 0, so
dec ecx ;i decrease ecx (result of this subrutine)
ret
For example,
If I put an array with 0,2 I expect ecx = 0, but with that input actually get 1.
With the array 1,2 I get 0 (which is what I want)
with the array 0,0 I get 1 (what I want, again)
Edit: tried starting the loop on n-1 and it's giving me even weirder results.
TOP:
xor ecx,ecx
;xor ebx,ebx
mov ecx,n-1
TOP_FOR:
;mov bx,word[eax+ecx*2]
cmp word[eax+ecx*2],0
je FIN_TOPE
dec ecx
cmp ecx,0
jne TOP_FOR
END_TOP:
ret
Your logic is totally backwards. Your cmp/je loop condition leaves the loop when you find the first non-zero. (And you've already incremented ECX after loading, but before checking it).
So after your loop, ECX = index of the element after the first non-zero element.
You at least 2 options:
remember the last-seen 0 in another register, and use it at the end of the loop
loop backwards, starting with ECX = n-1, and exit the loop on the first zero. (Or on dec ecx producing 0.)
One of these is obviously more efficient and easier than the other. :P
I'll leave it up to you to solve the off-by-1 problems, but probably you want to have the ecx < n or ecx >= 0 check at the bottom of the loop, e.g. dec ecx / jge TOP_FOR. i.e. a do{}while(--i) loop.
Also, normally EBX is a call-preserved register. You don't need to use it at all, though. cmp word [eax + ecx*2], 0 works fine.
Also in your current code, you read 2 bytes past the end of the array. potentially faulting if it was at the end of a page. (You don't use it, though, so it's not a correctness problem other than that.) You use ECX as an index before checking if it's too large! That problem goes away if you just use a memory, immediate cmp.
Also, normally a pointer-increment is more efficient. After the loop you can subtract and right-shift to get an index.

Loops in Assembly

I'm kind of a rookie at programming in Assembly, and I need some clarification on the following kind of loops (##, #B, #F).
When you have a routine like this:
Routine: PROC Value: Byte
MOV ECX, 3
MOVZX EDX, Value
MOV EAX, EDX
##: SHL EAX, 8
OR EAX, EDX
LOOP #B
RET
Routine: ENDP
, what do the ##, #B mean?
As I was told those kinds of loops have some particularities. #B points to the first ## in the routine and #F points to the last ## in the routine, am I right? Is there anything else regarding these loops that I should know of? (I was also told that whenever they appear the loop goes 3 times, but I'm not sure about that).
Thanks in advance.
## is a local label. You can put it on any code line in your program. It is valid until you define the next ## label. (Not the "first" or "last", just previous and next).
#b means "the previously (early source line) defined ## label". #f means "the next defined ## label".
The loop executes three times because the "LOOP" instruction decrements ECX (implicitly) on each iteration, and branches if the remaining value in ECX is not zero... and you loaded ECX with the value of 3 initially.
If you want to understand how the code works, you should assemble it using the MS Assembler, and then single step through it, looking at the registers as you go. Alternatively, read the Intel insturction set manually really carefully. (I did a lot of this when I first started programming the x86, and it was worth every minute, even for that huge document).

Assembly (MASMx86 PC) duplicating array

I'm working on an encryption project that's got me stumped. I need to apply a series of encryption keys to a string array in order to determine which key was used to encrypt the message. I have the code set up to run a loop which applies all keys within the range, but now i need a way to 'refresh' the original string array. My solution was to copy the original array into a new un-populated array of the same size, for each iteration of the loop. I wrote the following procedure to accomplish this:
CopyBuffer PROC
; Copies the original buffer into a storage variable
; recieves: nothing
; returns: nothing
pushad
mov ecx,67 ; loop counter
mov esi,0
L3:
mov dl,buffer[esi]
mov bufferCopy[esi],dl ; Store byte in array copy
inc esi ; point to the next byte
loop L3
popad
ret
CopyArray ENDP
The arrays referred to in the above code were declared as follows:
buffer BYTE 0e9h,0c8h,0d0h,087h,0ceh,0d4h,087h,0d3h,0cfh,0c2h,087h,0d3h,0ceh,0cah,0c2h,087h
BYTE 0c1h,0c8h,0d5h,087h,0c6h,0cbh,0cbh,087h,0c0h,0c8h,0c8h,0c3h,087h,0cah,0c2h,0c9h
BYTE 087h,0d3h,0c8h,087h,0c4h,0c8h,0cah,0c2h,087h,0d3h,0c8h,087h,0d3h,0cfh,0c2h,087h
BYTE 0c6h,0ceh,0c3h,087h,0c8h,0c1h,087h,0d3h,0cfh,0c2h,0ceh,0d5h,087h,0d7h,0c6h,0d5h
BYTE 0d3h,0deh
bufferCopy db 67 dup(0)
My code successfully populates the duplicate array. However the elements of the copy are different from the corresponding elements of the original array.
I'd really appreciate the wisdom of a more advanced assembly programmer on this one! I'm fairly new to the language, and still a bit fuzzy on syntax.
The code seems to be correct (regardless of its untidy style). The only observation is that the provided sample array has only 66 elements, not 67, so the first byte will be copied twice.
The problem is somewhere else. Try to run the program in the debugger and check the array immediately after the return of the procedure in order to proof its correctness.
Well, it seems
You are not using the loop counter that you have created and your loop is just running forever which in turn overwrites your copyBuffer array.
Try the lines
dec ecx
jnz L3
instedof loop L3 that should help.
Ok, first of all thanks to everyone for your suggestions! I've solved the problem (though probably not in the simplest way possible). First of all, i changed the declaration of bufferCopy from
bufferCopy db 67 dup(0)
to
bufferCopy BYTE SIZEOF buffer DUP(0),0
I think converting to a null terminated string solved some of my problems. Beyond that, i also ammended my CopyBuffer PROC to run as follows:
pushad
mov edx,OFFSET buffer
Call StrLength
mov bufSize,eax
mov ecx,bufSize
mov esi,0
L2:
mov al,buffer[esi]
mov bufferCopy[esi],al
inc esi
loop L2
popad
ret
The call to StrLength was probably a redundancy, considering i knew the length of the string to begin with. As a disclaimer, i'd like to add that i'm not exceptionally familiar with assembly yet. This solution (while functional) is by no means optimal. Furthermore, my explanations are cursory at best.

Accessing array members in assembler

I'm using C and ASM{} in one of our classes in order to complete an assembler project where we have to encrypt an input string, transmit and decrypt it.
The key is loaded into an empty C char array (20 chars long) and is then used later on with the XOR statement to encrypt.
The code to load the address of the array is:
lea esi, key
which puts the address of 'key' into esi. The address here is the same as the address of the key array when we examine the register in debug mode, so we know that works.
mov edx, [esi]
we thought this would move the value of esi's first index into edx, as we use "mov [esi], eax" to put the value of the a register into the esi array. The reverse seemed logical.
However, the value which edx actually gets is "875575655" (last run) or similar. Far too large for a char value.
I get the feeling we may be accessing the array wrong,
Any advice would be appreciated.
Note: Usually to increase the array index we're simply using inc esi and then read like we did above, this is how we were planning on reading from the array as well.
With mov edx, [esi] you read DWORD (because edx size is double word). Use mov dl, [esi] to read byte.
875575655 in hexa is 0x34303967, that would be string 'g904'.
To explain: while logically it's a character string, you can load more characters at once. So, instead of making 20 byte loads and xors, you can make 5 such operations on DWORD.

Resources