i'm struggling with learning assembly code so please don't hate me if this is a stupid question..
I'm trying to understand how to do loops, I have learned that to loop you use the following structure:
mov ECX, 3
l1:
<loop body?
loop l1
however, instead of 3 im trying to load the value of a variable (called 'first') however when I do this, it just seems to loop infinitely. This is the current code i've got:
lea eax, get1; ask for the first number
push eax
call printf
add esp, 4
lea eax, first; read it in
push eax
lea eax, format
push eax
call scanf
add esp, 8
mov ECX, first
l1:
/* test loop body */
lea eax, get1; ask for the first number
push eax
call printf
add esp, 4
loop l1
does anyone know where i'm going wrong?
Related
I'm trying to sort an array using the registers from biggest to least and nothing seems to be working. The ecx is my amount of numbers that I have, the esi is the address of my list which consists of dwords. I use the edx to keep going up by 4 bytes to each element. My code doesn't sort the entire array I know that I need to find the location of the max and then set it equal to the outer loops edx but I can't seem to figure out how to change the elements in the array because I only have the edx register. I tried pushing the location and then popping it back out when the inner loop was finished but that didn't seem to work. Please anything is appreciated I have been working on this problem for over 4 hours.
push ebp
mov ebp,esp
mov ecx,[ebp+8]
mov esi,[ebp+12]
mov edx,-4
outerloop:
add edx,4
push edx
push ecx
mov ebx,[edx+esi]
innerloop:
add edx,4
mov eax,[edx+esi]
cmp ebx,eax
jl change
finish:
loop innerloop
pop ecx
pop edx
loop outerloop
jmp done
change:
mov [edx+esi],ebx
mov [edx+esi-4],eax
sub edx,4
push edx
mov edx,offset change1
call writestring
pop edx
jmp finish
done:
pop ebp
ret 8
What you are looking for is a 'reversed' Bubble Sort (You can of course use any sorting algorithm you wish, but this is simple for an example). I'm not sure what assembler you're using, but here's a short assembly function that will accomplish a sort of n int32_t integers stored in array/list arr. (This example was written in NASM)
;int *sort(int *arr,int n);
sort:
push ebp
mov ebp,esp
mov edx,[ebp+12]
.loop1:
mov esi,[ebp+8] ;arr ptr
mov ecx,[ebp+12] ;n number of ints
.loop2:
mov eax,[esi] ;compare
mov ebx,[esi+4]
cmp eax,ebx
jg .skip
mov [esi],ebx ;swap
mov [esi+4],eax
.skip:
add esi,4 ;perform loop checks
dec ecx
cmp ecx,1
ja .loop2
dec edx
ja .loop1
mov eax,[ebp+8] ;return arr
mov esp,ebp
pop ebp
ret
Please keep in mind this example wasn't really optimized (e.g., it iterates too many times through the whole array). Sometimes (esp. in assembly languages), less is more. Instead of offsetting the pointer by ecx/edx, you can increment the array pointer (or a copy of it), and do comparisons using that directly. This way you don't have to keep track of a counter register AND the pointer at the same time. :)
I'm learning x86 assembly and I'm trying to write a program that reads a number n (2 digits) from user input and iterate n times.
I've tried many ways but I get an infinite loop or segment fault.
input:
push msgInputQty
call printf
add esp, 4
push quantity
call gets
add esp, 4
mov ecx, 2
mov eax, 0
mov ebx, 0
mov edi, 0
mov dl, 10
transform:
mul dl
mov ebx, 0
mov bl, byte[quantity+edi]
sub bl, 30h
add eax, ebx
inc edi
loop transform
mov ecx, eax
printNTimes:
push msgDig
call printf
add esp, 4
loop printNTimes
I'd like to save in ecx and iterate n times this number
Your ecx register is being blown away by the call to printf.
ecx is a volatile register in some calling conventions and its likely that your loop is being corrupted by what printf is leaving in there.
To begin with, I would follow Raymond's advice in the comment attached to your original question and attach a debugger to witness this behaviour for yourself.
As for a solution, you can try preserving ecx and restoring it after the call to see the difference:
; for example
mov edi,ecx
call printf
mov ecx,edi
There may be more issues here (hard to know for sure since your code is incomplete ... but things like your stack allocations that don't appear to be for any reason are interesting) - but that is a good place to start.
Peter has left a comment under my answer to point out that you could remove the issue and optimize my solution by just not using ecx for your loop at all and instead do it manually, making your code change:
mov edi, eax
printNTimes:
push msgDig
call printf
add esp, 4
dec edi
jnz printNTimes
The output for the given program should be 1--2--3--4--5--6--7--8.
However, mine keeps giving me 1--2--3--4--5--6--7-8--.I need to get rid of "--" after 8, but I couldn't figure out how to do it. Could someone help me, please?
INCLUDE Irvine32.inc
.data
arrayb byte 1,2,3,4,5,6,7,8
space byte "--",0
.code
main PROC
mov eax,0
mov edx,offset space
mov esi,offset arrayb
mov ecx, 8
printb:
mov al, [esi]
call writedec
call writestring
inc esi
mov eax, 8
loop printb
exit
main ENDP
end main
Your code (and loop specifically) currently does:
<init state>
counter = 8
printb:
output number
output "--"
loop to printb
<exit>
If you run through it in your head, it should be obvious why "--" is printed after last number.
There are many ways how to adjust that code, in real world code doing formatting I often either use some kind of join function which takes list and separator, and produces the formatted string, or if doing it manually, I would probably hardcode output of "1" ahead of loop, initialize the state to start loop as if starting from "2", and output "--" as first thing in the loop, i.e.:
<init state>
output number
advance state as if it was printed inside loop
counter = 8-1 ; one value is already out
printb:
output "--" ; the loop body starts with "--" output
output number
loop to printb
<exit>
I.e. in your code (with some modifications "improving" some things I didn't like :
...
mov edx,offset space
mov esi,offset arrayb
movzx eax, BYTE PTR [esi]
inc esi
call writedec
mov ecx, 8-1
printb:
call writestring
movzx eax, BYTE PTR [esi]
inc esi
call writedec
loop printb
exit
...
edit
The Peter Cordes idea from comments to make last item special case would maybe lead to better code in generic cases, where the amount of items is variable (with "8" fixed you know you can display first element and then 7 more will be looped).
Let's imagine such function in assembly, taking arguments in registers:
; esi = byte array to output
; ecx = amount of bytes
; will modify eax, ecx, edx, esi
OutputByteArray PROC
jecxz NoItemsToOutput ; if ecx=0
dec ecx
jz OutputLastItem ; if ecx=1, display only last item
; 1 < count, so "0 < ecx" here (ecx = count-1) => do the loop
mov edx,offset space
printb: ; output number and "--" "count-1" times
movzx eax, BYTE PTR [esi]
inc esi
call writedec
call writestring
loop printb
OutputLastItem:
movzx eax, BYTE PTR [esi]
call writedec
NoItemsToOutput:
ret
ENDP
I'm trying to take an array, add all the values in it, and then display them. Unfortunately for me, even though the following code builds, the output doesn't return the value which I am expecting.
For instance, one time when I ran it, I got
-2112902102
and another time I got
-1280521519
I'm assuming there's some sort of logic to that, but it doesn't exactly help me.
INCLUDE Irvine32.inc
.386
.stack 4096
ExitProcess proto,dwExitCode:dword
.data
array SBYTE 26, -81, -104, -57
total_sum SWORD ?
.code
main proc
mov esi, OFFSET array
mov ecx, LENGTHOF array
mov total_sum, 0
mov ebp,0
L1:
add ebp, [esi]
inc esi
loop L1
mov edx, ebp
call WriteInt
invoke ExitProcess,0
main endp
end main
And yes, I know that total_sum isn't doing anything at this point, but I first want to figure the rest out before implementing total_sum.
As you have been hinted, the problem is that you add dwords instead of bytes. The simple solution is to sign extend the byte into a temporary register before summing. That is replace this:
add ebp, [esi]
With:
movsx edx, byte ptr [esi]
add ebp, edx
And of course for printing you need to use eax, so change mov edx, ebp to mov eax, ebp. Or you could just use that to do the summing up directly.
Size contains the number 86.
var_10= dword ptr -10h
var_C= dword ptr -0Ch
size= dword ptr 8
push ebp
mov ebp, esp
sub esp, 28h
mov eax, [ebp+size]
mov [esp], eax ; size
call _malloc
mov ds:x, eax
mov [ebp+var_C], 0
jmp short loc_804889E
loc_804889E: ~~~~~~~~~~~~~~~~~~~~~
mov eax, [ebp+size]
sub eax, 1
cmp eax, [ebp+var_C]
jg short loc_8048887
loc_8048887: ~~~~~~~~~~~~~~~~~~~~~
mov edx, ds:x
mov eax, [ebp+var_C]
add edx, eax
mov eax, [ebp+var_C]
add eax, 16h
mov [edx], al
add [ebp+var_C], 1
I am having difficulties reversing this portion of a project I am working on. There's a portion of the code where ds:x is moved into edx and is added with var_c and I am unsure where to go with that.
To me the program looks like it calls malloc and then moves that into ds:x and then moves 0 to var_c.
After that it simply subtracts 1 from the size of my pointer array and compares that number to 0, then jumps to a portion where it adds ds:x into edx so it can add eax to edx.
Am I dealing with some sort of array here? What is the first value that's going to go into edx in loc_8048887? Another way this could help would be to see a C equivalent of it... But that would be what I am trying to accomplish and would rather learn the solution through a different means.
Thank you!
In x86 assembly there's no strict distinction between a variable stored in memory and an array in memory. It only depends on how you access the memory region. All you have is code and data. Anyway, I'd say that ds:x is an array as because of this code here:
mov edx, ds:x ; edx = [x]
mov eax, [ebp+var_C] ; eax = something
add edx, eax ; edx = [x] + something
mov eax, [ebp+var_C] ; eax = something
add eax, 16h ; eax = something + 0x16
mov [edx], al ; [[x] + something ] = al . Yes, ds:x is an array!
What is the value of edx in loc_8048887? To find it out you only need some very basic debugging skills. I assume you have gdb at hand, if not, get it ASAP. Then compile the code with debug symbols and link it, then run gdb with the executable, set a code breakpoint at loc_8048887, run the program with r, and finally check the value of edx.
These are the commands you need:
gdb myexecutable
(gdb) b loc_8048887
(gdb) r
(gdb) info registers edx