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
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 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.
I'm currently trying to learn Assembly, and one of the tasks I am given is to take user input integers and insert those numbers into an array. Once the array has 7 integers, I will loop through the array and print out the numbers. However, I'm currently stuck on how to insert the numbers into the array. Here is the code I have right now:
.DATA
inputIntMessage BYTE "Enter an integer: ", 0
inputStringMessage BYTE "Enter a string: ", 0
intArray DWORD 0,0,0,0,0,0,0
intCounter DWORD 0
user_input DWORD ?
.CODE
main PROC
mov eax, intCounter
mov edx, 0
top:
cmp eax, 7
je final1
jl L1
L1: intInput inputIntMessage, user_input
mov ebx, user_input
mov intArray[edx], ebx ;This is where I think the problem is.
add edx, 4
inc eax
jmp top
final1:
mov ecx, 0
mov edx, 0
printarrayloop:
cmp edx,7
jl L2
je next
L2: intOutput intArray[ecx]
add ecx, 4
inc edx
next:
next: just goes to the next problem; irrelevant to this inserting into an array problem. My thinking is that I should use the offset of the array, so I can access the address of each element in the array and directly change that, but I do not know how. Can someone point me in the right direction?
EDIT: When I run the program the window prompts the user to enter an integer 7 times (which is as intended), and then prints out the first number the user entered. However, the window should be printing out all of the numbers the user entered.
The primary reason why your code only prints one number is because the code that displays the array of numbers does this:
mov ecx, 0
mov edx, 0
printarrayloop:
cmp edx,7
jl L2
je next
L2: intOutput intArray[ecx]
add ecx, 4
inc edx
next:
What is missing is that you do not continue the loop after displaying the first number. You need to jump back to printarrayloop to process the next number. Add this right below inc edx:
jmp printarrayloop
There are some other things you may wish to consider. In this code:
top:
cmp eax, 7
je final1
jl L1
L1: intInput inputIntMessage, user_input
[snip]
final1:
You do cmp eax, 7. If it is equal you jump out. If it is less then you just branch to label L1 anyway. You can modify that code by removing the extraneous jl L1 branch and label. So you would have this:
top:
cmp eax, 7
je final1
intInput inputIntMessage, user_input
In this code there are some extra instructions that can be removed:
mov ecx, 0
mov edx, 0
printarrayloop:
cmp edx,7
jl L2
je next
L2: intOutput intArray[ecx]
add ecx, 4
inc edx
jmp printarrayloop
next:
Similar to the previous comment I made to compare EDX to 7 using cmp edx,7. You can simply say that after comparing if it is equal to 7 then you jump out of the loop to next . If it is less than 7 it will just continue and print the number out. So your code could look like this:
mov ecx, 0
mov edx, 0
printarrayloop:
cmp edx,7
je next
intOutput intArray[ecx]
add ecx, 4
inc edx
jmp printarrayloop
next:
x86 32-bit code has a scaled addressing mode (with displacement). You can find all the addressing modes described in this summary here and more detailed description here.
You can using a scaling factor (multiply a register by 1,2,4, or 8) when doing addressing. You have code that looks like this:
mov intArray[edx], ebx
add edx, 4
EDX points to the element number you wish to display, multiplying it by 4 will account for the fact that the size of a DWORD is 4 bytes. So you can remove the add edx, 4and change the code accessing the array to:
mov intArray[edx*4], ebx
intArray[edx*4] is an address that is equivalent to intArray+(edx*4)
You can make a similar change when you output. Delete this line:
add ecx, 4
And use scaled addressing with:
intOutput intArray[ecx*4]
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?
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