I am trying to write a nasm program that can move and print dynamic arrays using malloc and printf. The program sometimes crashes and sometimes works when it tries to print an array. When I edit the code so that it doesn't print anything, the program always works. The method "movad" sets a dynamic array equal to another array and "setad" sets an array to a static array that was declared at the beginning of the program. The array variable stores a pointer to a malloced piece of memory that stores the array. The first dword of the array is the length and the rest is the contents.
Here is the code:
%include "io.inc"
CEXTERN malloc
section .data
fmt: db "%c%c %c%c",0
start: dd 2
dd 'a'
dd 'b'
section .bss
array1: resd 1
array2: resd 1
a: resd 1
section .text
global _main
_main:
push ebp
mov ebp,esp
push dword start
push dword array1
call setad
add esp,8
push dword array1
push dword array2
call movad
add esp,8
mov ebx,[array2]
push dword [ebx+8]
push dword [ebx+4]
mov ebx,[array1]
push dword [ebx+8]
push dword [ebx+4]
push dword fmt
call printf
add esp,20
mov esp,ebp
pop ebp
ret
movad:
push ebp
mov ebp,esp
push ebx
push ecx
push edi
push esi
mov edi,[ebp+8]
mov esi,[ebp+12]
mov ebx,[esi]
push dword [ebx]
add dword [esp],4
call malloc
add esp,4
mov [edi],eax
mov ecx,[esi]
mov ecx,[ecx]
add ecx,1
mov edi,[edi]
mov esi,[esi]
cld
rep movsd
pop esi
pop edi
pop ecx
pop ebx
mov esp,ebp
pop ebp
ret
setad:
push ebp
mov ebp,esp
push eax
lea eax,[ebp+12]
push eax
push dword [ebp+8]
call movad
add esp,8
pop eax
mov esp,ebp
pop ebp
ret
How can I make it so that it never crashes when it prints something
Related
segment .data
array: db 68,222,29,68,33,234,179,103,37,85
fmt: db ",%d",0
segment .text
extern printf
global asm_main
asm_main:
enter 0,0 ; setup routine
pusha
push dword 10
push dword array
call print_array
add esp,8
push dword 10
push dword array
swap_byte_first_last:
mov eax,[array]
mov edx,[array+9]
mov [array+9],eax
mov [array],edx
call print_array
; don't delete anything following this comment
popa
mov eax, 0 ; return back to C
leave
ret
segment .data
ListFormat db ",%u", 0
segment .text
global print_array
print_array:
enter 0,0
push esi
push ebx
xor esi, esi
mov ecx, [ebp+12]
mov ebx, [ebp+8]
xor edx,edx
mov dl,[ebx + esi]
mov eax,edx
call print_int
dec ecx
inc esi
print_loop:
xor edx,edx
mov dl,[ebx + esi]
push ecx
push edx
push dword ListFormat
call printf
add esp, 8
inc esi
pop ecx
loop print_loop
call print_nl
pop ebx
pop esi
leave
ret
%define A_ADDR [ebp+12]
%define B_ADDR [ebp+8]
%define A_VAL [eax]
%define B_VAL [ebx]
segment .text
global swap_byte
swap_byte:
enter 0,0
pusha
mov eax, A_ADDR
mov ebx, B_ADDR
mov dl,A_VAL
mov cl,B_VAL
mov [eax],cl
mov [ebx],dl
popa
leave
ret
This prints 85,44,37,100,33,234,179,103,37,68. The result should be 85,222,29,68,33,234,179,103,37,68.
I was able to swap first element (68) with the last element (85), but numbers 222,29,and 68 have changed to 44,37,and 100. What changes do I need to make with the codes in swap_byte_first_last? Other parts of the code were given.
%include "asm_io.inc"
;
; initialized data is put in the .data segment
;
segment .data
array: dd 180,32,455,499,388,480,239,346,257,84
fmt: dd ",%d",0
; uninitialized data is put in the .bss segment
;
segment .bss
resd 10
;
; code is put in the .text segment
;
segment .text
extern printf
global asm_main
asm_main:
enter 0,0 ; setup routine
pusha
; The following is just example of how to print an array
push dword 10
push dword array
call print_array
add esp,8 ; clean up stack
; don't delete anything following this comment
popa
mov eax, 0 ; return back to C
leave
ret
segment .data
ListFormat db ",%u", 0
segment .text
global print_array
print_array:
enter 0,0
push esi
push ebx
xor esi, esi ; esi = 0
mov ecx, [ebp+12] ; ecx = n
mov ebx, [ebp+8]
xor edx, edx
mov dl, [ebx + esi] ; ebx = address of array
mov eax,edx
call print_int
dec ecx
inc esi
print_loop:
xor edx,edx
mov dl,[ebx + esi]
push ecx ; printf might change ecx!
push edx ; push array value
push dword ListFormat
call printf
add esp, 8 ; remove parameters (leave ecx!)
inc esi
pop ecx
loop print_loop
call print_nl
pop ebx
pop esi
leave
ret
So this code prints out 180,0,0,0,32,0,0,0,199,1 when I want to print out 180,32,455,499,388,480,239,346,257,84. I think that it's because this is designed to print byte words. I'm trying to print in double words and I'm guessing something in the print_array needs to be changed. I tried mov dl, [ebx+esi*4] but it still doesn't print the array that I want to print. Or does something else needs to be changed to print array of double words?
You could leave it at changing the mov dl, [ebx+esi] instruction into mov edx, [ebx+esi*4], but that would be just half the fun!
1 Why not try to make a loop that can deal with the special case of the first value in the list that doesn't need the comma prefix? No more using print_int.
2 Also don't use the LOOP instruction. It's slow! The pair cmp jb (that can macro-fuse) is much better.
3 And replacing the prolog enter 0,0 and epilog leave codes by simply addressing the parameters via ESP relative addressing is simple enough.
4 Always consider the special cases! What if the array happens to be empty?
print_array:
push ebx
push esi
mov ebx, [esp+12] ; Begin array
mov esi, [esp+16] ; n
test esi, esi
jz done
lea esi, [ebx+esi*4] ; End array
mov edx, ListFormat+1 ; "%u"
more: mov eax, [ebx] ; Array dword value
push eax
push edx ; "%u" first time, ",%u" others
call printf
add esp, 8
add ebx, 4 ; To next dword in the array
mov edx, ListFormat ; ",%u"
cmp ebx, esi ; Current address < Last address ?
jb more ; Yes
call print_nl
done: pop esi
pop ebx
ret
Under the right conditions, keeping ESP fixed inside this loop can be worth doing. See Peter Cordes' comments below this answer.
Next is a version of this code that keeps ESP fixed inside the loop:
print_array:
push ebx
push esi
mov ebx, [esp+12] ; Begin array
mov esi, [esp+16] ; n
test esi, esi
jz done
sub esp, 8 ; Space for the printf args
lea esi, [ebx+esi*4] ; End array
mov edx, ListFormat+1 ; "%u"
more: mov eax, [ebx] ; Array dword value
mov [esp+4], eax
mov [esp], edx ; "%u" first time, ",%u" others
call printf
add ebx, 4 ; To next dword in the array
mov edx, ListFormat ; ",%u"
cmp ebx, esi ; Current address < Last address ?
jb more ; Yes
call print_nl
add esp, 8
done: pop esi
pop ebx
ret
section .data
text db 'Put a number',10,0
scanform db '%d'
number dw 0
section .text
extern printf,scanf
global main
main:
push rbp
mov rbp,rsp
push rdi
push rsi
push rbx
mov rdi,text
mov rax,0
call printf
mov rsi,number
mov rdi,scanform
mov rax,0
call scanf
pop rbx
pop rsi
pop rdi
ret
This is my code I write a other codes all day and I do not have problem with these but now when I call scanf, write program received signal SIGSEV, segfault... Specified first and last line in different files. I do not understand this message can someone help me?
You have the following issues:
You forgot to pop rbp.
You misalign the stack which needs to be 16 byte aligned.
You do not zero terminate your format string (thanks to Paul for pointing this out).
You use %d which writes a 4 byte integer but you only allocated 2 bytes with dw.
It is recommended to align integers to 4 bytes.
A possible fixed version:
section .data
number dd 0
text db 'Put a number',10,0
scanform db '%d', 0
section .text
extern printf,scanf
global main
main:
push rbp
mov rbp,rsp
push rdi
push rsi
push rbx
push rbx ; for alignment
mov rdi,text
mov rax,0
call printf
mov rsi,number
mov rdi,scanform
mov rax,0
call scanf
pop rbx
pop rbx
pop rsi
pop rdi
pop rbp
ret
Since rsi and rdi are caller-saved registers and rbx is not touched, you can simplify the code. I also changed to xor zeroing and rip-relative addressing as follows:
section .data
number dd 0
text db 'Put a number',10,0
scanform db '%d', 0
section .text
extern printf,scanf
global main
main:
push rbp
lea rdi, [rel text]
xor eax, eax
call printf
lea rsi, [rel number]
lea rdi, [rel scanform]
xor eax, eax
call scanf
pop rbp
ret
I try to understand [c code -> assembly] code
void node::Check( data & _data1, vector<data2*>& _data2)
{
-> push ebp
-> mov ebp,esp
-> push ebx
if (TryToCheck(_data1.a, _data1.b))
-> mov ebx,dword ptr [_data1]
I'm not sure what this line does
What is the meaning of this line,
push esi
mov esi,ecx
ecx is a value for counting as I know .
Why save the value of ecx in esi?
mov eax,dword ptr [esi+50h]
What does this mean the value, 50h?
mov eax,dword ptr [eax+4]
lea edx,[ebx+40h]
lea ecx,[esi+50h]
push edx
lea edx,[ebx+50h]
push edx
call eax
test al,al
je node::Check+7Fh
push ebp
mov ebp,esp
This saves the caller's stackframe pointer (push ebp) and sets up your stackframe pointer (mov ebp,esp).
push ebx
This saves ebx on the stack. Somewhere later, before the return, you will see a pop ebx.
mov ebx,dword ptr [_data1]
This moves the content of location _data1 into the ebx register. The debugger shows you a symbolic name; if you would look more closely you will see move ebx,dword ptr [ebp+12]. Here the parameters of the caller are accessed using your stackframe pointer in ebp.
push esi
mov esi,ecx
This saves esi and then moves the value of ecx into esi.
mov eax,dword ptr [esi+50h]
This moves the value of the memory location at esi+50h into eax.
Sometimes you musn't worry too much about the assembler the compiler generates. It maybe sub-optimal or may be so optimized that you can't recognize your original statements.
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 ;)