using ebp/esp in conjunction with edi/esi - c

I'm working on a project that is implementing functions in assembly and calling them in C. Doing this requires working with EBP and ESP. [EBP + 8] is pointing to the beginning of a string that I want to reverse in my assembly function. I was going to do this:
cmp esi, edi
jge reversed
mov al, [esi]
mov bl, [edi]
mov [esi], bl
mov [edi], al
inc esi
dec edi
jmp reverse_string
I can find the end of the null terminated string just fine if I can use esi and edi pointers. Do I need to use a different way? Does everything have to be index offsets?

If [EBP + 8] holds the string pointer you could just move it to ESI and proceed from there.
mov esi,[ebp+8]
mov edi,esi
mov al,0
mov ecx,-1
cld
repne scasb ; find the NULL terminator
dec edi
.... your original code follows

Related

Allocate a vector of bytes on stack in assembly x86

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

Assembly x86-32 and some c functions

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'.

How to reverse an array is assembly?

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

memory corrupt using assembler procedure

I've written this procedure in asm:
.586
.model flat, stdcall
.xmm
.data
.code
EncryptAsm proc plainText:ptr byte, heigth:DWORD, inputLength:DWORD, encryptedText:ptr byte, cipherArray:ptr byte
local addRow:WORD
local row:DWORD
local column:DWORD
local iterator:DWORD
local forLoopIteratorI:DWORD
local forLoopIteratorJ:DWORD
push esi
push edi
push ebx
push ecx
push edx
mov addRow,0
mov row,0
mov column,0
mov iterator,0
mov forLoopIteratorI,0
mov forLoopIteratorJ,0
mov ecx,heigth
FILL_CIPHER_ARRAY_LOOP: mov eax, inputLength
cmp iterator,eax
jge PREPARE_ITERATOR
push ecx ;pushing heigth value
mov ecx,row ;calculating index of cipher array index=[row*inputLength+column]
imul ecx,inputLength
add ecx,column
mov eax,iterator
mov edx,plainText
mov al,[edx+eax]
mov [esi],al
mov ebx, cipherArray
mov [ebx+ecx],al
movsb
pop ecx;getting back heigth value
add column,1
cmp addRow,0
je INC_ROW
cmp addRow,0
jne DEC_ROW
INC_ROW: add row,1
jmp ROW_COMPARE
DEC_ROW: sub row,1
jmp ROW_COMPARE
ROW_COMPARE: cmp row,ecx
jge IF_STATEMENT_1
cmp row,0
jl IF_STATEMENT_2
jmp INCREMENT_ITERATOR
IF_STATEMENT_1: sub row,2
mov addRow,1
jmp INCREMENT_ITERATOR
IF_STATEMENT_2: add row,2
mov addRow,0
jmp INCREMENT_ITERATOR
INCREMENT_ITERATOR: add iterator,1
jmp FILL_CIPHER_ARRAY_LOOP
PREPARE_ITERATOR: mov iterator,0
READ_CIPHER_ARRY_LOOP_I:cmp forLoopIteratorI,ecx
jge PREPARE_ITERATOR_2
READ_CIPHER_ARRY_LOOP_J:mov eax, inputLength
cmp forLoopIteratorJ,eax
jge PREPARE_I_AND_J
push ecx ;pushing heigth value
mov ecx,forLoopIteratorI ;calculating index of cipher array
imul ecx,inputLength
add ecx,forLoopIteratorJ
mov ebx,cipherArray
mov al,[ebx+ecx]
cmp al,'#'
jne COPY_VALUE
ITERATE: add forLoopIteratorJ,1
pop ecx
jmp READ_CIPHER_ARRY_LOOP_J
PREPARE_I_AND_J: mov forLoopIteratorJ,0
add forLoopIteratorI,1
jmp READ_CIPHER_ARRY_LOOP_I
COPY_VALUE: push edi
mov edi,iterator
mov edx,encryptedText
mov [edx+edi],al
add iterator,1
pop edi
jmp ITERATE
PREPARE_ITERATOR_2: mov iterator,0
FINISH: mov eax, encryptedText
pop edx
pop ecx
pop ebx
pop edi
pop esi
ret
EncryptAsm endp
end
It implements rail fence cipher algorithm (at the end the variable encryptedText contains ciphered plainText). It works fine, I mean it does the encryption well but after all I'm getting memory corrupt error... I'm calling this procedure as an extern one from C app. I can print the encrypted text without any problem but when returning 0 in main function, the memory corrupt error pops up.
I don't know what can cause it. At the beginning of asm procedure, I push all the registers' values and pop them after the whole operation.
The error message:
Unhandled exception at 0x72676F74 in ConsoleApplication12.exe: 0xC0000005: Access violation executing location 0x72676F74.
I'll be greatful for any hint.
One possible candidate could be here:
mov edx,plainText
mov al,[edx+eax]
mov [esi],al
esi is pushed, from the caller, but where is it initialized? It seems that it uses whatever is there from the caller. Same for edi so where will movsb store it?
UPDATE
Since I don't know your algorithm and don't see how it is used I can only guess. BUt I think you should do the following before the loop:
mov esi, plainText
mov edi, encryptedText
mov ebx, cipherArray
Since you don't change these values you can then change this code:
COPY_VALUE: push edi
mov edi,iterator
mov edx,encryptedText
mov [edx+edi],al
add iterator,1
pop edi
jmp ITERATE
to this:
COPY_VALUE: mov edx,iterator
mov [edx+edi],al
inc iterator
jmp ITERATE
Generally instead of using add x, 1 you can use inc x which is shorter.
People I've found it! The cause of the error was... 'movsb'. I was using it in a previous version of my algorithm and I've forgotten to delete it... The rest of my code works fine. Thanks for all the answers and for willing to help m ;)

Assembly EAX register resetting without reason

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

Resources