I'm trying to write a simple program that reverses an array. It almost works, well it works for the first half of the array anyway. The term in the middle is always "0" and then it returns to the pattern. For example, if I input: 1,2,3,4,5,6,7,8,9,10, the output will be 10,9,8,7,6,0,6,5,4,3. The order of the program is basically this:
Call to ReverseArray:
INVOKE ReverseArray,
LENGTHOF array, SIZEOF array, TYPE array, OFFSET array
ReverseArray procedure (loops through the array and calls mSwap32):
ReverseArray PROC,
len:DWORD, s:DWORD, increment:DWORD,address:DWORD
mov edx, OFFSET revArray
call WriteString
mov edi, address
mov esi, address
add esi, s
sub esi, TYPE array
mov ecx, len
shr ecx, 1
L2:
mSwap32 edi, esi
add edi, increment
sub esi, increment
loop L2
ret
ReverseArray endp
mSwap32 Macro (is given two addresses to swap):
mSwap32 MACRO address1:REQ, address2:REQ
mov edi, address1
mov esi, address2
mov eax, [esi]
push eax
mov eax, [edi]
mov [esi], eax
pop eax
mov [edi], eax
ENDM
I'm fairly certain that the error is in mSwap32...I'm sure it is some small logical error I'm missing, but no matter how much I toy with it I can not figure it out. ??
it's a WORD array
With this crucial piece of information we can solve the problems. LENGTHOF will be 10 (as before), SIZEOF will now be 20 and TYPE will now be 2.
ReverseArray PROC,
len:DWORD, s:DWORD, increment:DWORD,address:DWORD
mov edx, OFFSET revArray
call WriteString
mov edi, address
mov esi, address
add esi, s
sub esi, increment ;Better not refer to the actual array here!
mov ecx, len
shr ecx, 1
L2:
mSwap32 edi, esi
add edi, increment
sub esi, increment
loop L2
ret
ReverseArray endp
and the macro:
mSwap32 MACRO address1:REQ, address2:REQ
mov edi, address1
mov esi, address2
mov ax, [esi]
push eax
mov ax, [edi]
mov [esi], ax
pop eax
mov [edi], ax
ENDM
Shorter and still using a macro:
mSwap32 MACRO address1:REQ, address2:REQ
mov edi, address1
mov esi, address2
mov ax, [esi]
xchg ax, [edi]
mov [esi], ax
ENDM
Related
I try to put on stack the values contained by array_output but every time I print the values from the stack it prints just 0s.
If I try to print the array simple not using the stack it works.
What I do wrong?
stack_alloc:
sub esp, 1
mov al, byte [array_output + ecx]
mov byte [esp], al
add ecx, 1
cmp ebx, ARRAY_OUTPUT_LEN
cmp ebx, ecx
jg stack_alloc
cmp ebx, ARRAY_OUTPUT_LEN
cmp ebx, ecx
jg stack_alloc
You have a typo in your code. The cmp ebx, ARRAY_OUTPUT_LEN instruction should not be comparing but rather loading the EBX register.
You could correct the problem replacing the cmp with a mov but I would propose to simplify your code and just compare the index in ECX to ARRAY_OUTPUT_LEN. This will require choosing the opposite conditional branch and saves from using the additional register EBX:
xor ecx, ecx
stack_alloc:
sub esp, 1
mov al, [array_output + ecx]
mov [esp], al
inc ecx
cmp ecx, ARRAY_OUTPUT_LEN
jb stack_alloc
I never learn C language so it makes me confuse. I just like to know if I did it correctly or where I need to improve. For this code I used assembly x86 32 bit. Thanks
This is what I supposed to do:
Write a procedure with the signature
char *strchar(char *s1, char c1)
that returns a pointer to the first occurrence of the character c1 within the string s1 or, if not found, returns a null.
This is what I came out with:
strchar (char*, char):
push ebp
mov ebp, esp
mov dword ptr [ebp-24], edi
mov EAX , esi
mov BYTE PTR [ebp-28], al
.L5:
mov EAX , dword ptr [ebp-24]
movzx EAX , byte ptr [ EAX ]
test AL, AL
je .L2
mov EAX , dword PTR [ebp-24]
movzx EAX , BYTE PTR [ EAX ]
cmp BYTE PTR [ebp-28], al
jne .L3
mov eax, dword PTR [ebp-24]
jmp .L6
.L3:
add dword PTR [ebp-24], 1
jmp .L5
.L2:
LEA eax, [ebp-9]
MOV DWORD PTR [EBP-8], eax
MOV EAX, DWORD PTR [ebp-8]
.L6:
POP EBP
RET
The lines:
mov dword ptr [ebp-24], edi
mov EAX , esi
mov BYTE PTR [ebp-28], al
assume that a stack frame has been allocated for this function which doesn’t appear true; I think you should have something like:
sub esp, 32
after the
mov ebp,esp
Also, the three lines after L2 seem confused. The only way to get to L2 is if the nil (0) byte is discovered in the string, at which point, the code should return a NULL pointer.
The exit path in the code (L6) leaves eax alone, so all that should be needed is:
L2:
mov eax, 0
It might make debugging easier if you kept the alias up to date; so:
L2:
mov eax, 0
mov [ebp-24], eax
Also, the calling convention used here is a bit odd: the string is passed in edi and the character in esi. Normally, in x86-32, these would both be passed on the stack. This looks like it might have been x86-64 code, converted to x86-32....
A final note; this assembly code looks like the output of a compiler with optimisations disabled. Often, generating the assembly with the optimisations enabled generates easier to understand code. This code, for example, could be much more concisely written as below, without even devolving into weird intel ops:
strchar:
mov edx, esi
mov eax, edi
L:
mov dh, [eax]
test dh, dh
jz null
cmp dh, dl
je done
inc eax
jmp L
null:
mov eax, 0
done:
ret
Here is one with stack overhead
[global strchar]
strchar:
push ebp
mov ebp, esp
mov dl, byte [ebp + 12]
mov ecx, dword [ebp + 8]
xor eax, eax
.loop: mov al, [ecx]
or al, al
jz .exit
cmp al, dl
jz .found
add ecx, 1
jmp .loop
.found: mov eax, ecx
.exit:
leave
ret
Here is one without stack overhead
[global strchar]
strchar:
mov dl, byte [esp + 8]
mov ecx, dword [esp + 4]
xor eax, eax
.loop: mov al, [ecx]
or al, al
jz .exit
cmp al, dl
jz .found
add ecx, 1
jmp .loop
.found: mov eax, ecx
.exit:
ret
These are using the 'cdecl' calling convention. For 'stdcall' change the last 'ret' to 'ret 8'.
I have written some code for an assignment involving Assembly, and one part of the assignment involves finding the minimum value between two user inputted indexes (I and J). For the life of me I can not get it to work as the loop does not iterate properly and I cannot figure out why. Any help would be appreciated.
MinValues PROC
mov eax, PosI ;getting difference between i and j
sub PosJ, eax
mov eax, PosJ
Call WriteInt
mov IJDiff, eax
call crlf
mov ecx, IJDiff
LEA esi, Vector
add esi, PosI
add esi, PosI
add esi, PosI
add esi, PosI
mov eax, [esi]
mov MinNum, eax
NextMin:
mov eax, [esi]
call WriteInt
cmp eax, MinNum
jl Minimum
add esi, 4
Loop NextMin
ret
Minimum: mov MinNum, eax
;add esi, 4
ret
MinValues ENDP
My task here is to add a code that sorts the array with insertion sort.
'printf' function prints a string
printArray prints the array
For some reason the array doesn't get sorted, and i cant find the reason why.
Help will be appreciated.
main:
push MSG ; print welcome message
call printf
add esp,4 ; clean the stack
call printArray ;print the unsorted array
;;;;;;;;;;add code here;;;;;;;;;;
mov eax,1
loop1:
mov ebx, array
add ebx, eax
loop2:
mov esi, ebx
dec esi
mov esi, [esi] ;esi holds the value before what ebx points to
cmp [ebx], esi
ja endLoop2
mov edx, esi
mov esi, ebx
dec esi
mov ecx, [ebx]
mov [esi], ecx
mov [ebx], edx
dec ebx
cmp ebx, array
ja loop2
endLoop2:
inc eax
cmp eax, 11
jbe loop1
;;;;;;;end of your code;;;;;;;;;;;;;;
call printArray
mov eax, 1 ;exit system call
int 0x80
If your array is full of 1 byte values, use movb instead of mov when loading and storing to memory.
I have the following assembly code:
; File: strrev.asm
; A subroutine called from C programs.
; Parameters: string A
; Result: String is reversed and returned.
SECTION .text
global strrev
_strrev: nop
strrev:
push ebp
mov ebp, esp
; registers ebx,esi, and edi must be saved if used
push ebx
push edi
xor esi, esi
xor eax, eax
mov ecx, [ebp+8] ; load the start of the array into ecx
jecxz end ; jump if [ecx] is zero
mov edi, ecx
reverseLoop:
cmp byte[edi], 0
je reverseLoop_1
inc edi
inc eax
jmp reverseLoop
reverseLoop_1:
mov esi, edi ;move end of array into esi
mov edi, ecx ;reset start of array to edi
reverseLoop_2:
mov al, [esi]
mov bl, [edi]
mov [esi], bl
mov [edi], al
inc edi
dec esi
dec eax
jnz reverseLoop_2
end:
pop edi ; restore registers
pop ebx
mov esp, ebp ; take down stack frame
pop ebp
ret
Which works fine until you start looping through reverseLoop_2. Using gdb, eax is listed as being 11, which it should be (this is the length of the string I passed in through a separate c program). This is show in the debugger as:
Breakpoint 2, reverseLoop_2 () at strrev.asm:40
40 mov al, [esi]
(gdb) display $eax
1: $eax = 11
However, if I step through the program to the next line, it resets to 0.
(gdb) next
41 mov bl, [edi]
1: $eax = 0
I need eax to be preserved since its the one keeping track of how many times reverseLoop_2 needs to loop. Why is it resetting to 0 after the call to mov?
If you're using eax as a loop counter, you shouldn't write to it inside the loop :
reverseLoop_2:
mov al, [esi]
Remember that al is the least significant byte of eax :
I think this should work.
mov eax, address of your string
push esi
push edi
mov edi, eax
mov esi, eax
; find end of string
sub ecx, ecx
not ecx
sub al, al
cld
repne scasb
; points to the byte after '0x00'
dec edi
dec edi
; main loop will swap the first with the last byte
; and increase/decrease the pointer until the cross each other
_loop:
cmp esi, edi ; if both pointers meet, we are done
jg _done
mov al, [edi]
mov bl, [esi]
mov [esi], al
mov [edi], bl
inc esi
dec edi
jmp _loop
_done:
pop edi
pop esi