I make program in order to find maximum depth of parenthesis in String.
At first, I make C program with Assembly code, it works good:
#include <stdio.h>
int main(){
char *s ="((abc) ∗ (ab+(ab)∗(cdx7)))−xxab((()))c";
int x;
asm volatile (
".intel_syntax noprefix;"
"mov eax,%1;"
"lea ebx,[eax];"
"xor eax,eax;" ecx - currentDepth, edx - MaxDepth
"xor ecx,ecx;"
"xor edx,edx;"
"loop:"
"mov al,[ebx];"
"or al, al;" // check if end of string
"jz print;" // if end jump to print
"cmp al, '(';"
"je increase;"
"cmp al,')';"
"je decrease;"
"inc ebx;" // next char
"jmp loop;"
"increase:"
"inc ecx; cmp edx,ecx;js changeMax;inc ebx;jmp loop;"
"changeMax:"
"mov edx,ecx; inc ebx; jmp loop;"
"decrease:"
"dec ecx;inc ebx;jmp loop;"
"print:"
"mov %0, edx;"
".att_syntax prefix;"
: "=r" (x)
: "r" (s)
: "eax", "ebx", "ecx", "edx"
);
printf("%d", x);
return 0;
}
But I have to make it in pure Assembler with .s extension, so i try this:
.intel_syntax noprefix
.globl main
.text
main:
mov eax,offset expr
lea ebx,[eax]
xor eax,eax
xor ecx,ecx
xor edx,edx
loop:
mov al,[ebx]
or al,al
jz print
cmp al,'('
je increase
cmp al,')'
je decrease
inc ebx
jmp loop
increase:
inc ecx
cmp edx,ecx
js changeMax
inc ebx
jmp loop
changeMax:
mov edx,ecx
inc ebx
jmp loop
decrease:
dec ecx
inc ebx
jmp loop
print:
push edx
call printf
data:
mesg: .ascii "%d\n"
expr: .ascii "((x))"
But I got segmentation fault(core dumped)
Maybe labels are working differently than in first program in c.
But I don't know, please help me.
UPDATE
Thank you Jester
I edited label print, now it print out the result, but after that I still get segmentation fault.
print:
push edx
mov edx, offset mesg
push edx
call printf
ret
Ok, I remove it from the stack. Now i don't get segmentation fault, but after the result i have some rubbish text
print:
push edx
mov edx, offset mesg
push edx
call printf
add esp,8
ret
xor edx,edx
ret
Output:
2
f�f��UWVS������×
Update 2
Ok, everything works right now, I use string from command line ./a.out '((x))'
Someone can check that everything is ok.
.intel_syntax noprefix
.globl main
.text
main:
pop eax #return address
pop eax #return argc
pop eax #return argv
mov eax,[eax+4] #argv[1]
sub esp,12 #return stack to the right position
lea ebx,[eax]
xor eax,eax
xor ecx,ecx
xor edx,edx
loop:
mov al,[ebx]
or al,al
jz print
cmp al,'('
je increase
cmp al,')'
je decrease
inc ebx
jmp loop
increase:
inc ecx
cmp edx,ecx
js changeMax
inc ebx
jmp loop
changeMax:
mov edx,ecx
inc ebx
jmp loop
decrease:
dec ecx
inc ebx
jmp loop
print:
push edx
mov edx, offset mesg
push edx
call printf
add esp,8
ret
mov edx,0
ret
data:
mesg: .asciz "%d\n"
Related
I have elements loaded in stack and I need to move them to array. My code looks like this:
%include "asm_io.inc"
segment .data
array db 100 dup(0)
length db 0
segment .text
global _asm_main
extern getchar
_asm_main:
enter 0, 0
pusha
call getchar
char_loop:
mov ebx,10
sub eax, '0'
mul ebx
mov ebx, eax
call getchar
sub eax, '0'
add eax, ebx
push eax
inc BYTE[length]
call getchar
cmp eax, 10
je fill_array
cmp eax, 13
je fill_array
cmp eax, 32
je skip_spaces
jmp char_loop
skip_spaces:
call getchar
cmp eax, 32
je skip_spaces
jmp char_loop
fill_array:
mov ecx, [length]
mov ebx, array
l1:
pop eax
mov [ebx], eax ; should be al instead of eax
inc ebx
call print_int
call print_nl
loop l1
print_array:
mov ecx, [length]
mov ebx, array
l2:
mov eax, [ebx] ; should be al instead of eax
call print_int
call print_nl
inc ebx
loop l2
_asm_end:
call print_nl
popa
mov eax, 0
leave
ret
print_int in asm_io.asm is
print_int:
enter 0,0
pusha
pushf
push eax
push dword int_format
call _printf
pop ecx
pop ecx
popf
popa
leave
ret
Where int_format is int_format db "%i",0
Length and values in stack are correct, I had them printed but when I try to print array only last value is correct. Other values are random numbers. I tried combinations of registers of different sizes but it did not work. I think that error has to do something with size of registers or size of array.
Answer here:
As #xiver77 said in comments I was writing into array 4 bytes instead 1 byte. One element in array has 1 byte and I tried to write 4 bytes. That creates overflow of bites and change other elements in array. Instead mov [ebx], eax should be mov [ebx], al and mov eax, [ebx] for printing should be mov al [ebx].
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
I'm trying to read 3 numbers from the user and I store them in an array then I show them using paul carter functions in NASM here is my code :
%include "asm_io.inc"
SECTION .bss
tab resb 3
SECTION .data
msg db "Un nombre :",10
SECTION .text
global main
main:
mov esi,tab
xor ecx,ecx
get_data:
mov eax,msg
call print_string
call read_int
mov [esi+ecx],eax
inc ecx
cmp ecx,3
jne get_data
call print_nl
xor ecx,ecx
mov edi,tab
print_data:
mov eax,[edi+ecx]
call print_int
inc ecx
cmp ecx,3
jne print_data
mov eax,1 ; exit code
int 0x80 ; call exit
The problem is that is doesn't execute print_data loop and it exit .
Just to be clear. Are these the changes you did? Even if the ECX register is not used as an input or output for a particular function it might still be used internally. That's what Michael meant with 'ecx is typically caller-saved'
%include "asm_io.inc"
SECTION .bss
tab resd 3
SECTION .data
msg db "Un nombre :",10,0
SECTION .text
global main
main:
mov edi,tab
xor ecx,ecx
get_data:
push ecx
mov eax,msg
call print_string
call read_int
mov [edi+ecx*4],eax
pop ecx
inc ecx
cmp ecx,3
jne get_data
call print_nl
mov esi,tab
xor ecx,ecx
print_data:
push ecx
mov eax,[esi+ecx*4]
call print_int
pop ecx
inc ecx
cmp ecx,3
jne print_data
mov eax,1 ; exit code
int 0x80 ; call exit
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.