How to play chords in ASM 8086? - audio

I want to know what is the best way to play more then 1 note at the time in assembly.
If you can, please add a procedure that explain your answer.
Thanks!

Orange, next code is a program a made long time ago in EMU8086 and Windows XP (it ran at that time). Now I have Windows 8 64 bits and it doesn't run anymore. I will give you the code because it may help you. All the names and comments are in spanish because I am costarrican, but the assembler code is universal (google translator will give you a hand):
.model small
.stack 100h
.data
;----------------------------------------------------------------------------
MENSAJEPLAY DB ' PROYECTO ® PIANO ¯',13,10
DB 13,10
DB ' LAS TECLAS DE LAS NOTAS VAN EN EL ORDEN SIGUIENTE:',13,10
DB 13,10
DB ' 2 3 5 6 7' ,13,10
DB ' q w e r t y u',13,10,13,10
DB 13,10
DB ' s d g h j' ,13,10
DB ' z x c v b n m',13,10,13,10
DB ' PARA TERMINAR PRESIONE ESC','$'
;----------------------------------------------------------------------------
.code
TONO MACRO NUMERO ;Esta macro recibe el tono
MOV BX,NUMERO ;y manda a llamar a los procedimientos
CALL BOCINA
ENDM
;----------------------------------------------------------------------------
CLRSCR PROC
;Limpia la pantalla
MOV AH,6
XOR AL,AL
XOR CX,CX
MOV DX,184FH
MOV BH,13
INT 10H
RET
ENDP
;----------------------------------------------------------------------------
BocinaOn PROC ;Activa la bocina
IN AL, 61h
OR AL, 11B
OUT 61h, AL
RET
BocinaOn ENDP
;----------------------------------------------------------------------------
BocinaOff PROC ;Desactiva la bocina
IN AL, 61h
AND AL, 11111100b
OUT 61h, AL
RET
BocinaOff ENDP
;----------------------------------------------------------------------------
Ajustar PROC ;Ajusta la bocina con la frecuencia dada
PUSH BP
MOV BP, SP
MOV DX, 18
MOV AX, 13353
MOV BX, [BP + 4]
DIV BX
MOV BX, AX
MOV AL, 0B6h
OUT 43h, AL
;ENVIAR AL PUERTO LA FRECUENCIA EN DOS BYTES POR SEPARADO.
MOV AX, BX
OUT 42h, AL ;ENVIA PRIMER BYTE. (PUERTO PARALELO = 378H)
MOV AL, AH
OUT 42h, AL ;ENVIA SEGUNDO BYTE. (PUERTO SERIAL = 3F8H)
POP BP
RET
Ajustar ENDP
;----------------------------------------------------------------------------
Suena proc ;Activa la bocina y coloca el nombre de
CALL bocinaON ;la tecla.
MOV AX,40H
MOV ES,AX
MOV DX,ES:[006EH]
MOV AX,ES:[006CH]
ADD AX,7
ADC DX,0 ;Se le suma 7 unidades a ese valor
CLIC:
CMP DX,ES:[006EH] ;Y se compara hasta que sean iguales
JB FINI ;Pasando por un ciclo, cuando llegen
JA CLIC ;a ser iguales se sale del ciclo y
CMP AX,ES:[006CH]
JA CLIC
FINI:
CALL BocinaOff ;Se desconecta la bocina y regresa.
RET
Suena endp
;----------------------------------------------------------------------------
Bocina proc ;Este procedimiento guarda AX y BX en
PUSH BX ;la pila para no perder su valor, con
MOV AX, BX ;esto llama a ajusta y a suena
PUSH AX
CALL Ajustar ;Pone la frecuencia en el puerto.
POP AX
POP BX
CALL SUENA ;Activa el speaker y lo desactiva.
ret
Bocina endp
;----------------------------------------------------------------------------
;CONVERTIR A MINUSCULA SI ERA MAYUSCULA
MINUSCULA PROC
CMP AL, 65 ;'A'
JB CONTINUAR ;SI LA TECLA ES MENOR QUE LA 'A' NO HACE NADA
CMP AL, 90 ;'Z'
JA CONTINUAR ;SI LA TECLA ES MAYOR QUE LA 'Z' NO HACE NADA
ADD AL, 32 ;Convierte may£scula en min£scula.
CONTINUAR:
RET
MINUSCULA ENDP
;----------------------------------------------------------------------------
;CAPTURA LA TECLA CON LA NOTA QUE EL USUARIO DESEA.
TECLA PROC
MOV AH,8 ;Si la hay, obtiene la nota
INT 21H
CALL MINUSCULA
RET
TECLA ENDP
;----------------------------------------------------------------------------
;Cicla el programa hasta que el usuario presione la tecla ESC.
;El procedimiento reacciona a las teclas indicadas en el segmento de datos.
;Cualquier otra tecla es ignorada.
;La tecla presionada es convertida a min£scula, ya que la tabla ASCII
;trata distinto unas de otras.
;Despu‚s de que cada tecla es presionada, el ciclo vuelve al inicio y
;se repite.
;Si la tecla presionada corresponde a una nota musical, el c¢digo
;correspondiente es enviado al parlante.
SPEAKER PROC
COMIENZA:
CALL TECLA
CMP AL,'q' ;DO alto
JNE S1 ;SI NO ES LA TECLA ESPERADA, SALTA PARA VERIFICAR LA SIGUIENTE.
TONO 523 ;SI ES LA TECLA ESPERADA, GENERA EL SONIDO CORRESPONDIENTE
JMP COMIENZA ;DESPUES DEL SONIDO REINICIA PARA ESPERAR OTRO SONIDO.
S1: CMP AL,'w' ;RE alto
JNE S2
TONO 587
JMP COMIENZA
S2: CMP AL,'e' ;MI alto
JNE S3
TONO 659
JMP COMIENZA
S3: CMP AL,'r' ;FA alto
JNE S4
TONO 698
JMP COMIENZA
S4: CMP AL,'t' ;SOL alto
JNE S5
TONO 784
JMP COMIENZA
S5: CMP AL,'y' ;LA alto
JNE S6
TONO 880
JMP COMIENZA
S6: CMP AL,'u' ;SI alto
JNE S8
TONO 988
JMP NOSALTO1
SALTO1:
JMP COMIENZA
NOSALTO1:
JMP COMIENZA
S8: CMP AL,'2' ;DO# alto
JNE S9
TONO 554
JMP COMIENZA
S9: CMP AL,'3' ;RE# alto
JNE S10
TONO 622
JMP COMIENZA
S10: CMP AL,'5' ;FA# alto
JNE S11
TONO 740
JMP COMIENZA
S11: CMP AL,'6' ;SOL# alto
JNE S12
TONO 830
JMP COMIENZA
S12: CMP AL,'7' ;SIb alto
JNE S13
TONO 923
JMP COMIENZA
S13: CMP AL,'z' ;DO bajo
JNE S14
TONO 261
JMP COMIENZA
S14: CMP AL,'x' ;RE bajo
JNE S15
TONO 293
JMP COMIENZA
S15: CMP AL,'c' ;MI bajo
JNE S16
TONO 329
JMP NOSALTO2
SALTO2:
JMP SALTO1
NOSALTO2:
JMP COMIENZA
S16: CMP AL,'v' ;FA bajo
JNE S17
TONO 349
JMP COMIENZA
S17: CMP AL,'b' ;SOL bajo
JNE S18
TONO 392
JMP COMIENZA
S18: CMP AL,'n' ;LA bajo
JNE S19
TONO 466
JMP COMIENZA
S19: CMP AL,'m' ;SI bajo
JNE S20
TONO 498
JMP COMIENZA
S20: CMP AL,'s' ;DO# bajo
JNE S21
TONO 277
JMP COMIENZA
S21: CMP AL,'d' ;RE# bajo
JNE S22
TONO 311
JMP COMIENZA
S22: CMP AL,'g' ;FA# bajo
JNE S23
TONO 370
JMP COMIENZA
S23: CMP AL,'h' ;SOL# bajo
JNE S24
TONO 415
JMP COMIENZA
S24: CMP AL,'j' ;SIb bajo
JNE S25
TONO 515
JMP COMIENZA
S25: CMP AL,27 ;27 = tecla ESC (terminar).
JNE SALTO2
RET
SPEAKER ENDP
;----------------------------------------------------------------------------
MENSAJE PROC
MOV AH,9
LEA DX,MENSAJEPLAY
INT 21H
RET
MENSAJE ENDP
;----------------------------------------------------------------------------
EMPIEZA:
MOV AX, #data ;se mandan llamar todos los
MOV DS, AX ;procedimientos
CALL CLRSCR ;Limpiar pantalla.
CALL MENSAJE ;Despliega la explicaci¢n del programa.
CALL SPEAKER ;Sonidos.
MOV AX, 4C00H
INT 21H
;----------------------------------------------------------------------------
END EMPIEZA
What it does is to show you a the keys to press in order to make the notes to sound. You can open it in EMU8086 and run it, but the speaker interrupts behave weird because of Windows 8.
Orange just edited the question, now he wants simultaneous notes playing. Well, my code doesn't do that, it plays one note at a time. For two or more notes to play at the same time we would requiere threads or processes executing that way.
I am not sure assembler can do that, not even sure if the speaker, controlled by an interruption, is allowed to do it. This is because something called "reentrancy", or something like that, it refers to the problem caused when an interrupt is executed when it is already executing, usually the program halts when it happens.

Related

Concatenate two string in asm x86-64 intel syntax

I have tried to concatenate two strings but I keep getting segmentation faults, somebody could help me on what might be wrong with my code? Thanks!
To test it i just create to strings with dynamically allocated memory, this is a class exercise so I must free memory from the 2 parameters my fucntion gets
my code:
;int32_t strCmp(char* a, char* b)
strConcat:
push rbp ;stack frame
mov rbp, rsp
push r12 ; stringA
push r13 ; stringB
push r14 ; puntero inicio ; stringA
push r15 ; puntero inicio ; stringB
mov r12, rdi
mov r13, rsi
mov r14, r12
mov r15, r13
xor rcx, rcx ;clean rcx to do len(stringA)+leng(stringB)+1
call strLen ; len stringA
add rcx, rax
mov rdi, r13
call strLen ; len stringB
add rcx, rax
mov rdi, rcx
inc rdi
call malloc
; now rax has a pointer to new concatenated string space
.cicloA: ;loop to iterate over 1st string
cmp byte [r12], 0
jz .cicloB
xor rdx, rdx
mov dl, byte [r12]
mov byte [rax], dl
inc r12
inc rax
jmp .cicloA
.cicloB: ;loop to iterate over 2th string
cmp byte [r13], 0
jz .fin
xor rdx, rdx
mov dl, byte [r13]
mov byte [rax], dl
inc r13
inc rax
jmp .cicloB
.fin:
;add /0
mov byte [rax], 0
;release memory
mov rdi, r14
call free
mov rdi, r15
call free
pop r15
pop r14
pop r13
pop r12
pop rbp
ret
And my strLen function is
;uint32_t strLen(char* a)
strLen:
push rbp ;armo el stack frame
mov rbp, rsp
xor rax,rax
.avanzar: ;loop para ver si llegue al fin de un string
cmp byte [rdi], 0
je .fin
inc rdi
inc rax
jmp .avanzar
.fin:
pop rbp
ret
Valgrind Error:
==18885== Invalid read of size 1
==18885== at 0x400E4A: ??? (lib.asm:79)
==18885== by 0x400C49: test_strConcat (main.c:79)
==18885== by 0x400D28: main (main.c:109)
==18885== Address 0x2 is not stack'd, malloc'd or (recently) free'd
In the end, I reworte the fuction strConcat from scratch and now it works.
strConcat:
push rbp ;armo el stack frame
mov rbp, rsp
push rbx
push r12 ; stringA
push r13 ; stringB
sub rsp, 0X08
mov r12, rdi
mov r13, rsi
call strLen ;loongitud del primer string
mov ebx, eax
mov rdi, r13
call strLen ;longitud del segundo string;
add ebx, eax
mov edi, ebx
add edi, 1
call malloc
; ahora rax tiene el puntero a nuevo string para concatenar
;limpio contadores
xor r8, r8
xor r9, r9
.cicloA: ;loop para colocar stringA en nuevo string
cmp byte [r12 + r8], 0
jz .cicloB
mov dl, byte [r12 + r8]
mov byte [rax + r8], dl
inc r8
jmp .cicloA
.cicloB: ;loop para colocar stringB en nuevo string
cmp byte [r13 + r9], 0
jz .borrar
mov dl, byte [r13 + r9]
mov byte [rax + r8], dl
inc r8
inc r9
jmp .cicloB
.borrar:
;agrego el cero al final
mov byte [rax + r8], 0
mov rbx, rax
;reviso si son el mismo puntero
cmp r12, r13
je .igualitos
;libero memoria
mov rdi, r12
call free
mov rdi, r13
call free
jmp .final
.igualitos:
mov rdi, r12
call free
.final:
add rsp, 0x08
mov rax, rbx
pop r13
pop r12
pop rbx
pop rbp
ret

Assembly project, adding line numbers to text using YASM on the Intel i386 architecture

I have to create an assembly program using YASM on the i386 architecture (32 bits) that receives a text as a parameter and returns a text with the same text but with each line numbered.
Example:
00 this is what the final text should look like
01 all lines numbered
02 and the last line should have the amount of total lines
03 Total lines:3.
; $ yasm -f elf enum.asm
; $ ld -o enum enum.o
; $ ./fibonacci
%define stdout 1
section .data
file_name db 'test.txt'
new_file db 'resultado.txt'
num db "00: ",4,
numL equ $ - num
bufferEntradaL dd 1
salto db 0xa
section .bss
descriptorEntrada resb 2
bufferEntrada resb 2
descriptorSalida resb 2
descriptorEntrada resb 2
punteroBuffer resb 2
cant resb 2
section .text
global _start
abrirArchivoLectura:
;Abre un archivo
mov EAX, sys_open ; Llamo a sys_open
mov ECX, 0 ; Solo lectura
mov EBX file_name ; Nombre del archivo
int 80h ; Llamo al sistema
ret
abrirArchivoEscritura:
mov EAX, sys_open ; Llamo al sys_open
mov ECX, 1 ; Modo solo escritura
mov EBX new_file ; Nombre del archivo
int 80h ; Llamo al sistema
ret
crearArchivoEscritura:
mov EAX, sys_create
mov EBX new_file
mov ECX, 1
int 80h
ret
leerArchivo:
;Lee un archivo
mov EAX, sys_read ; Llamo a sys_read
mov EBX, [descriptorEntrada] ; Descriptor del archivo
mov ECX, bufferEntrada ; Buffer de entrada
mov EDX, bufferEntradaL ; Tamaño del buffer
int 80h ; Llamo al sistema
ret
imprimirMensaje:
;Imprime un mensaje de ayuda
mov EAX, sys_write ; Llamo a sys_write
mov EBX, stdout ; Imprimir por pantalla
mov ECX, num ; Mensaje a imprimir
mov EDX, numL ; Longitud
int 0x80 ; Llamo al sistema
jmp salirSinError ; Sale sin error
imprimirSaltoPantalla:
;Imprime un salto de linea por pantalla
mov EAX, sys_write ; Llamo a sys_write
mov EBX, stdout ; Imprimir por pantalla
mov ECX, salto ; Mensaje a imprimir
mov EDX, 1 ; Longitud
int 0x80 ; Llamo al sistema
ret
cerrarArchivoEntrada:
;Cierra el archivo de entrada
mov EAX, sys_close ; Llamo a sys_close
mov EBX, [descriptorEntrada] ; Muevo el descriptor de salida al registro EBX
int 80h ; Llamo al sistema
ret
cerrarArchivoSalida:
;Cierra el archivo de salida
mov EAX, sys_close ; Llamo a sys_close
mov EBX, [descriptorSalida] ; Muevo el descriptor de salida al registro EBX
int 80h ; Llamo al sistema
ret
leerHastaSaltoLinea:
mov [punteroBuffer],ECX ; Le asigna a la variable punteroBuffer el contenido del registro ECX
mov [cant],EAX ; Le asigna a la variable cant el contenido del registro EAX
cmp cant,salto
jne leerHastaSaltoLinea
loop:
_start:
;Comienza el programa
call
call abrirArchivoLectura ; Abre el archivo de entrada
test EAX,EAX ; Testea que el parametro ingresado por el usuario sea un archivo.txt
js salirErrorArchivoEntrada ; Si no es un archivo.txt sale con un error de archivo de entrada
mov [descriptorEntrada],EAX ; Guardo el descriptor del archivo de entrada
call leerArchivo ; Lee el archivo de salida
call leerHastaSaltoLinea
salirErrorArchivoEntrada:
;Salir con error en archivo de entrada
mov EAX,sys_exit ; Llamo a sys_exit
mov EBX, 2 ; Finalizo por error en el archivo de entrada
int 0x80 ; Llamo al sistema
One obvious algorithm if you're just using read/write system calls directly is to allocate a 2nd buffer (large enough to hold the result even if every byte of input is a newline). Pages that you never touch don't really count as used, so it's fine to have a very large BSS.
In a loop:
do {
format the current line-number counter as a string, into the current position of the output buffer, plus a trailing space or tab. (NASM/YASM example How do I print an integer in Assembly Level Programming without printf from the c library? easy to port from x86-64 to i386.) But it would be more efficient to avoid re-doing the div-by-10 stuff every time, and just increment the least-significant digit until it's > '9', then redo the formatting.)
copy bytes from the input buffer up to and including the next newline ('\n' = 0xa. YASM doesn't support NASM's backtick-string / character literals that process C-style escape sequences). Also make sure you stop at the end of the buffer if it doesn't end with a newline. (You could check for this before the loop and append one if there isn't one, so simplifying your loop).
} while(input_pos < end_of_input)
When you're done, find the length of the result by subtracting the current position from the start of the buffer, and use that for a sys_write.
If you want to support files larger than your input/output buffer, remember whether you were at the end of a line or not when looping back to do another sys_read. (Instead of actually copying that partial line back to the beginning of the input buffer. The copying strategy would fail with a line longer than your buffer size.)
Don't forget that sys_read and sys_write can return early, having read or written fewer bytes than you asked, even if there are more bytes to read/write. (e.g. if you're reading from a pipe, including a named pipe, or if a signal came in during the system call). IIRC, the libc wrapper functions might handle retrying.
An alternative might be to scan through counting newlines, then work from the end of the buffer to expand it in-place. This would be slightly more cache-efficient, but it has the downside of needing an initial scan to count newlines to figure out how much space you'll need to leave (and what line number to count down from).
My first suggestion has the advantage that you only touch each input character once, instead of twice for this one. If you use a small-ish buffer that fits in L1D cache (like 16kiB), then expanding it in-place from the end might be worth considering, but it's more complex.
OTOH, if you're really trying to optimize for efficiency, you could maybe use vmsplice(2) to "gift" some pages to the kernel, into a temporary pipe and from there splice them into a regular file. So the physical pages you wrote end up as part of the pagecache with zero-copy. This might have more overhead than just making write() system calls, though.
Both of the previous methods have the advantage of only making one large write() system call for a whole buffer. It would also be possible to make an inefficient program that copies line-number + a line into a tmp buffer and uses sys_write on that, or even worse sys_write the line number text and then sys_write the line in-place in the input buffer.
IDK if that's any easier to implement, because you still have to get all the byte-counts right, and it sucks for performance. A sys_write is pretty slow compared to copying a few bytes.

My string isn't printing

I am doing an Assembly Calculator, and I need to do a Menu, but my program only prints the first string.
TITLE CALCULADORA
.MODEL SMALL
.STACK 100H
.DATA
;menu
MENU DB 'MENU$'
MSOMA DB 'Digite 1 para Soma$'
MSUB DB 'Digite 2 para Subtração$'
.CODE
MAIN PROC
MOV AX,#DATA ;Localizacao do endereco de memoria das variaveis, e colocando-os en AX
MOV DS,AX ;transferindo as dados da memoria em seu local padrao, no caso, DS (Data Stack)
LEA DX,MENU ;Colocando o endereco do menu em DX
MOV AH,9 ;funçao de exibicao de string
INT 21H ;execucao de AH
CALL PULA_LINHA ;"Chamando" a funcao PULA_LINHA
LEA DX,MSOMA ;Colocando o endereco do menu em DX
MOV AH,9 ;funçao de exibicao de string
INT 21H ;execucao de AH
CALL PULA_LINHA ;"Chamando" a funcao PULA_LINHA
MAIN ENDP
PULA_LINHA PROC
MOV AH,2 ;inicia a funçao de leitura de caracter
MOV DL,0DH ;caracter para o cursor retornar a posicao inicial
INT 21H ;executando o conteudo de AH, que por sua vez printa o conteudo de DL
MOV DL,0AH ;caracter de descer a linha
INT 21H ;executando a tarefa
PULA_LINHA ENDP
MOV AH,4CH ;saida do dos
INT 21H ;saindo
END MAIN
As Michael already mentioned in his comment, you "messed up" the returning functions a bit, and mistaken "return to OS" and "return to Caller":
TITLE CALCULADORA
.MODEL SMALL
.STACK 100H
.DATA
;menu
MENU DB 'MENU$'
MSOMA DB 'Digite 1 para Soma$'
MSUB DB 'Digite 2 para Subtração$'
.CODE
MAIN PROC
MOV AX,#DATA ;Localizacao do endereco de memoria das variaveis, e colocando-os en AX
MOV DS,AX ;transferindo as dados da memoria em seu local padrao, no caso, DS (Data Stack)
LEA DX,MENU ;Colocando o endereco do menu em DX
MOV AH,9 ;funçao de exibicao de string
INT 21H ;execucao de AH
CALL PULA_LINHA ;"Chamando" a funcao PULA_LINHA
LEA DX,MSOMA ;Colocando o endereco do menu em DX
MOV AH,9 ;funçao de exibicao de string
INT 21H ;execucao de AH
CALL PULA_LINHA ;"Chamando" a funcao PULA_LINHA
; ----------------------------------------------------------<<<<
; HERE you want to quit to OS, so the INT 21h/4Ch goes here
MOV AH,4CH ;saida do dos
INT 21H ;saindo
; ----------------------------------------------------------<<<<
MAIN ENDP
PULA_LINHA PROC
MOV AH,2 ;inicia a funçao de leitura de caracter
MOV DL,0DH ;caracter para o cursor retornar a posicao inicial
INT 21H ;executando o conteudo de AH, que por sua vez printa o conteudo de DL
MOV DL,0AH ;caracter de descer a linha
INT 21H ;executando a tarefa
; ----------------------------------------------------------<<<<
; HERE you just want to return to the caller, that's done with
RET
; ----------------------------------------------------------<<<<
PULA_LINHA ENDP
END MAIN

Wrong result after multiple read

I was wondering i someone could help me with my code, i want to read more than one time from the stdin in x86 but when i read the second time, it is ignoring the number and just add the 50. I want it to work so that i can call it as many times as i need to go adding the register EAX by an arbitrary number (which i will load from variables A,B,etc later on)
section .text
global _start
_start:
call leer
call atoi
add eax,10
call itoa
call imprimir
call limpiar
call leer
call atoi
add eax,50
call itoa
call imprimir
jmp salir
;-----------ATOI
atoi:
mov esi,Buffer ;move buffer address
mov eax,0 ;where im going to keep result
mov ebx,0 ;where i put char
.atoi_start:
mov bl, byte[esi] ;get the char
je .end_atoi
cmp bl, '0' ;check if null
jb .end_atoi
cmp bl,'9'
ja .end_atoi
imul eax,10 ;multiplico resultado por 10
sub bl,0x30 ;ascii->int
add eax,ebx ;agegue el nuevo digito
inc esi ;getting ready for next char
jmp .atoi_start
.end_atoi:
ret ;at this point i have int representation in eax
;-----------ITOA
itoa:
mov ebx, eax ;mueve el numero en eax a ebx
mov esi, Buffer
mov ebx,10
add esi,10
.itoa2:
xor edx,edx
div ebx
add dl,'0' ;lo convierte en char
mov [esi],dl
dec esi
test eax,eax
jnz .itoa2
jz .doneItoa
.doneItoa:
ret
;----------------------LIMPIAR
limpiar:
;limpia buffer usando eax
xor eax,eax;
xor edx,edx
xor ecx,ecx
mov ecx, 1100 ;tamano de veces que voy a limpiar
lea edx, [Buffer] ;direccion inicial del buffer
.loop:
mov [edx+ecx],eax ;voy a limpiar de atras para adelante
dec ecx ;decremento contador y verifico si es 0 para seguir limiando
jnz .loop
ret
imprimir:
mov eax,4
mov ebx,1
mov ecx,Buffer
mov edx,1100 ;tamano
int 0x80 ;syscall
;ahora imprimo nueva linea
mov eax,4
mov ebx,1
mov ecx,nuevaLinea
mov edx,1
int 0x80
ret
leer:
;vamos a poner el msg en pantalla
mov eax,4 ;sys_write
mov ebx,1 ;stdout
mov ecx,msg ;paso el mensaje
mov edx,lenMsg ;paso el largo del mensaje
int 80h
;ahora leemos
mov eax,3 ;sys_read
mov ebx,2 ;stdin
mov ecx,Buffer
mov edx,1100
int 80h
ret
salir:
mov rax,60 ;sys_exit
mov rdi,0 ;codigo de salida
syscall
section .data
msg db 'Ingrese un numero: '
lenMsg equ $-msg
nuevaLinea db 10;nueva linea
A dq 0
section .bss
Buffer: resb 1100
B: resb 1100
In atoi, the fifth instruction
je .end_atoi
tests the Z flag which has not been set in this function. So it is jumping based on the value of Z from whatever happened before atoi is called, which is the read system call in leer.
Either put
test bl, bl
before that je instruction or just remove the je, since the end of string will be caught by the cmp '0' that follows.
But that's not a complete fix: The read system call doesn't null terminate the input. Leer should use the number of bytes read (returned by the read system call) to place a null byte in the buffer after the input.

Nasm increment register over 9 can't display

this is my code wrote in NASM
This code is find string s2 in string s1, return index if found or return -1 if not found.
My trouble is my EBX (index), it increase 1,2,3,..9 ok but when inc to 10, they will show ':' or 11 it show ';'
I don't know why? Please help
Many thanks
Sorry for my bad English
; DINH VAN KIET
; TUAN 3
; Find String 32bit
; Build
; nasm -f elf find_string_32bit.asm -o find_string_32bit.o ; file object will be created
; ld -m elf_i386 -o find_string_32bit find_string_32bit.o ; link the object file and create executable file
; MO TA
; Tim chuoi s2 trong chuoi s1
SYS_EXIT EQU 1
SYS_READ EQU 3
SYS_WRITE EQU 4
STDIN EQU 0
STDOUT EQU 1
%define LEN 64 ; do dai toi da
%define LEN_STT 2
segment .data
msgS1 db 'Nhap chuoi s1: '
msgS1Len equ $ - msgS1
msgS2 db 'Nhap chuoi s2 (can tim): '
msgS2Len equ $ - msgS2
pos dw 00
segment .bss
s1 resw LEN
s2 resw LEN
temp resb 1
segment .learn
global _start
_start:
mov edx,msgS1Len
mov ecx,msgS1
call display
mov edx,LEN
mov ecx,s1
call read
mov edx,msgS2Len
mov ecx,msgS2
call display
mov edx,LEN
mov ecx,s2
call read
; dung eax de xu ly chuoi s2
mov eax,[s2]
mov edx,0 ; dung edx lam index
; dung ecx de xu ly chuoi s1
mov ecx,s1
mov ebx,-1 ; dung ebx de dem
lap1:
; kiem tra het chuoi
cmp byte[ecx],0
je done
; duyet tung ki tu cua s2
mov eax,[s2+edx]
mov [temp],eax
; de test
;push ebx
;push edx
;push ecx
;mov edx,1
;mov ecx,temp
;call display
;pop ecx
;pop edx
;pop ebx
; dua cac ki tu vao thanh ghi al va ah de so sanh
mov al,byte[ecx]
mov ah,[temp]
cmp ah,0xA ; kiem tra xem da het chuoi s2 hay chua?
je done
inc ebx ; tang bien vi tri
inc ecx ; tang index cua ecx
cmp al,ah ; kiem tra xem ki tu co khop nhau hay ko?
je meet
jne miss
jmp lap1
; Neu khop
meet:
cmp edx,0
jne met
push ebx
inc edx ; tang bien edx de kiem tra tiep s2
jmp lap1
; Neu tiep tuc khop
met:
inc edx
jmp lap1
; Neu khong khop
miss:
mov edx,0 ; dua edx ve dau s2 de kiem tra lai
jmp lap1
; Neu tim thay
found:
; in ra vi tri tim thay
pop ebx
add ebx,'0'
jmp exit
; Neu khong tim thay
notfound:
; in ra -1
mov ebx,'-1'
jmp exit
done:
cmp edx,0
je notfound
jne found
exit:
mov [pos],ebx
mov edx,2
mov ecx,pos
call display
mov eax,SYS_EXIT
int 80h
display:
mov eax,SYS_WRITE
mov ebx,STDOUT
int 80h
ret
read:
mov eax,SYS_READ
mov ebx,STDIN
int 80h
ret
The problem is you are displaying a number as a character.
add ebx, '0'
is a good way to convert a digit to a character for display. It is a bad way to convert a number to a character for display.
You want the following:
; variable in ebx
itoa:
mov eax, ebx
mov ecx, 10
mov esi, buf + 10
xor edx, edx
.nxt
div ecx
add dl, '0'
dec esi
mov [esi], dl
or eax, eax
jnz .nxt
mov edx, buf + 10
sub edx, esi
ret
; pointer in esi, length in edx
;... (bss area)
buf resb 10

Resources