data
tekst: .ascii "heLLo WoRlD 93a9s\0"
tekst_len = . - tekst
.text
.global _start
_start:
mov $tekst_len, %edx
petla:
cmp $tekst_len, %edx
je koniec
cmpb $'a', tekst(,%edx,1)
jg zamien #?????????????????????????????????????
inc %edx
jmp petla
zamien:
movb $'X', tekst(,%edx,1)
inc %edx
jmp petla
koniec:
movl $4, %eax
movl $1, %ebx
movl $tekst, %ecx
movl $tekst_len, %edx
int $0x80
I have such a problem: the instruction 'jg zamien' doesn't work. No matter what condition I choose 'jl', 'je' it never executes. Can someone tell me why?
This is the reason:
mov $tekst_len, %edx
petla:
cmp $tekst_len, %edx <-- edx will equal $tekst_len here on the first iteration
je koniec
You're always jumping to koniec on the first iteration of the loop.
The mov should probably be mov $0,%edx.
Related
So I have written a program based on NASM that receives user input (two numbers to be exact), and then it realizes the addition and difference between the two numbers, and then it prints it back. The program works fine in NASM but I am having trouble with GAS. The subroutine that counts the length of a string using the repne scasb instruction is giving me a headache because of a segmentation fault.
I have checked the code for segmentation faults, and I have located the fault in the repne scasb line.
What I am basically doing is translating a NASM code I made into its respective GAS code. However, as I said before, it's giving me a segmentation fault. After I get the first number from the user, to be more specific.
.section .data
msg: .ascii "Insert a number: "
msgLen = .-msg
msg2: .ascii "Insert another number: "
msg2Len = .-msg2
errorMsg: .ascii "Error: invalid character!\n"
errorMsgLen = .-errorMsg
displaySuma: .ascii "The result of the addition is: "
displaySumaLen = .-displaySuma
displayResta: .ascii "The result of the difference is: "
displayRestaLen = .-displayResta
enterChar: .ascii "\n"
terminator: .byte 0
.section .bss
.lcomm num1, 8
.lcomm num2, 8
.lcomm buffer, 10
.lcomm buffer2, 10
.section .text
.global _start
_start:
call _clear #clear registers. Probably an useless routine
call _msg1 #Display msg1
call _num1 #Read num1
movl num1, %edi
call _lenString #ECX now has num1 length
lea (num1), %esi
call _stringToInt #EAX now has num1 in integer
movl %eax, %r15d #R15D now has the integer
call _msg2 #Display msg2
call _num2 #Read num2
xor %edi, %edi #Clear EDI
movl num2, %edi #Moving num2 to EDI register to call _lenstring
xor %ecx, %ecx #Clear ECX
call _lenString #ECX has num2 length
xor %esi, %esi #clear ESI
lea (num2), %esi
call _stringToInt #EAX now has integer value of num2
mov %eax,%r14d ###R14D has num2 now
#Addition
#r8d = num1 + num2
mov %r15d, %r8d
add %r14d, %r8d #R8D has num1 + num2
#Difference
#If num1 > num2 =======> r9d = num1 - num2
#If num1 < num2 =======> r9d = num2 - num1
cmp %r14d, %r15d
jg .greater
mov %r14d, %r9d
sub %r15d, %r9d #R9D has num1 - num2
jmp .next
.greater:
mov %r15d, %r9d
sub %r14d, %r9d #R9D has num2 - num1
jmp .next
.next:
mov %r8d, %eax #Sum is now at EAX to convert it to ascii characters
lea (buffer), %esi
call _intToString
#EAX ascii of the sum
mov %eax, %r10d #Using R10D to store the new string
mov %r9d, %eax #Difference result is now at EAX
lea (buffer2), %esi
call _intToString
#EAX has the pointer to the difference result.
mov %eax, %r11d #Storing string in R10D
xor %edi, %edi
xor %r15d, %r15d
xor %r14d, %r14d
mov %r10d, %edi
call _lenString #ECX length of sum string
mov %ecx, %r15d #R15D now has that value
call _suma #This prints the sum result
xor %edi, %edi #Clear EDI
mov %r11d, %edi
call _lenString #ECX has length of dif. string
mov %ecx, %r14d #R14D has that value
call _resta #Print dif. result
movl $1, %eax #End of the program
movl $0, %ebx
int $0x80
_stringToInt:
xor %ebx, %ebx
.next_digit:
movzxb (%esi), %eax
cmp $0x30, %eax #These 4 lines check for invalid characters
jb _errorMsg
cmp $0x39, %eax
ja _errorMsg
inc %esi
sub $0x30, %eax ###Sub 48 (converts to integer)
imul $10, %ebx
add %eax, %ebx #ebx = ebx*10 + eax
loop .next_digit #loop [ECX] times
mov %ebx, %eax
ret
_intToString:
add $10, %esi
mov (terminator),%esi
mov $10, %ebx
.next_digit1:
xor %edx, %edx
div %ebx
add $0x30, %edx ##
dec %esi
mov %dl, (%esi)
test %eax, %eax
jnz .next_digit1
mov %esi, %eax
ret
#######################################################################################################
_msg1:
movl $4, %eax #msg1 routine
movl $1, %ebx
movl $msg, %ecx
movl $msgLen, %edx
int $0x80
ret
_num1:
movl $3, %eax #Reads first number
movl $0, %ebx
movl $num1, %ecx
movl $8, %edx
int $0x80
ret
_msg2:
movl $4, %eax #msg2 display
movl $1, %ebx
movl $msg2, %ecx
movl $msg2Len, %edx
int $0x80
ret
_num2:
movl $3, %eax #Reads the next number
movl $0, %ebx
movl $num2, %ecx
movl $8, %edx
int $0x80
ret
_salir:
movl $1, %eax #Exit
movl $0, %ebx
int $0x80
_errorMsg:
movl $4, %eax #Error msg
movl $1, %ebx
movl $errorMsg, %ecx
movl $errorMsgLen, %edx
int $0x80
jmp _salir
_lenString:
xor %ecx, %ecx
not %ecx
xor %al, %al
mov $0xA, %al
cld
repne scasb #Segmentation fault is caused by this line
not %ecx
dec %ecx
ret
_suma:
movl $4, %eax
movl $1, %ebx
movl $displaySuma, %ecx
movl $displayRestaLen, %edx
int $0x80
movl $4, %eax
movl $1, %ebx
mov %r10d, %ecx
mov %r15d, %edx
int $0x80
movl $4, %eax
movl $1, %ebx
movl $enterChar, %ecx
movl $1, %edx
int $0x80
ret
_resta:
movl $4, %eax
movl $1, %ebx
movl $displayResta, %ecx
movl $displayRestaLen, %edx
int $0x80
movl $4, %eax
movl $1, %ebx
mov %r11d, %ecx
mov %r14d, %edx
int $0x80
movl $4, %eax
movl $1, %ebx
movl $enterChar, %ecx
movl $1, %edx
int $0x80
ret
_clear:
xor %eax, %eax
xor %ebx, %ebx
xor %ecx, %ecx
xor %edx, %edx
xor %esi, %esi
xor %edi, %edi
xor %r8d, %r8d
xor %r9d, %r9d
xor %r10d, %r10d
xor %r11d, %r11d
xor %r14d, %r14d
xor %r15d, %r15d
ret
I am using this makefile to create the .o and .exe files (Given by my professor):
#*************************************************
# Executable name : hola
# Version : 2.0
# Created date : February 12, 2019
# Authors :
# Eduardo A. Canessa M
# Description : simple makefile for GAS
# Important Notice: To be used for GAS only
#*************************************************
#change the name "ejemplo" for the name of your source file
name=addSubInteger
#program to use as the assembler (you could use NASM or YASM for this makefile)
ASM=as
#flags for the assember
#ASM_F= #*** place here flags if needed ***
#program to use as linker
LINKER=ld
#link executable
$(name): $(name).o
$(LINKER) -o $(name) $(name).o
#assemble source code
$(name).o: $(name).s
$(ASM) $(ASM_F) -o $(name).o $(name).s
There is a segmentation fault error after the program reads the first user input.
This is the NASM code of my program (Hope you don't mind the spanish comments in it, but it's essentially the same program as the one written on GAS).
I know I have made some next level spaghetti code, but this is the solution I came to.
movl num1, %edi
call _lenString #ECX now has num1 length
lea (num1), %esi
call _stringToInt #EAX now has num1 in integer
The first instruction does not load the address in %edi. You can use lea like you did for the call to _stringToInt that follows next. Or if you care about a shorter encoding then write mov $num1, %edi.
lea (num1), %edi
call _lenString #ECX now has num1 length
The same problem exists for the second number:
movl num2, %edi SAME PROBLEM
xor %ecx, %ecx
call _lenString
The _intToString subroutine has 2 problems!
You destroy the address in %esi by writing a random value in it.
You (try to) write in memory beyond the buffer that was reserved via .lcomm buffer, 10. This will destroy the first byte in buffer2.
Since converting a 32-bit integer can produce (at most) 10 characters, you will need to enlarge your buffer to 11 bytes so you can safely store the byte-sized terminator.
.lcomm buffer, 11
.lcomm buffer2, 11
Then use this code:
_intToString:
mov $10, %ebx
add %ebx, %esi #Instead of 'ADD $10, %ESI' now that EBX==10
mov (terminator), %dl
mov %dl, (%esi)
.next_digit1:
xor %edx, %edx
div %ebx
add $0x30, %edx ##
dec %esi
mov %dl, (%esi)
test %eax, %eax
jnz .next_digit1
mov %esi, %eax
ret
The original NASM source uses
STRING_TERMINATOR equ 10
An equ does not consume memory at run-time. Your terminator: .byte 0 does use run-time memory! A good translation for the equ would be
.set terminator,0
Now you can write
_intToString:
mov $10, %ebx
add %ebx, %esi #Instead of 'ADD $10, %ESI' now that EBX==10
movb $terminator, (%esi)
I wanna have a beep inside of assembler.
like
beep()
Is this possible?
I have tried to use the sysCall write with the BELL-Symbol.
But it doesn't do anything.
I use the Linux-64-Nasm Assembler, And, as I am building a compiler, I don't want to use the C-libraries.
section .data
cmp_BLANK: db 0x0a
cmp_interr: db "error, You have typed in a non-Integer Character!", 0x0a
cmp_interrlen: equ $-cmp_interr
cmp_buffer: times 9 db 0x00
cmp_beep: db 0x07
section .bss
section .text
global _start
_start:
call func_main
mov eax, 1
mov ebx, 0
int 80h
func_main:
mov eax, 4
mov ebx, 1
mov ecx, cmp_beep
mov edx, 1
int 80h
ret
But I don't get a Sound. Even when I run it with sudo.
OK, first here is a reference doc: http://www.cs.binghamton.edu/~reckert/220/8254_timer.html
Look at the C implementation as example: https://github.com/torvalds/linux/blob/master/drivers/input/misc/pcspkr.c#L49
And here is the beeping code in GNU asm:
# send "set tune" command
movb $0xB6, %al
outb %al, $0x43
# nanosleep to let the IO complete
movl $0x1000, %eax
1: subl $1, %eax
cmpl $0, %eax
jne 1b
# set 220Hz, 0x152F == 1193180 / 220
movb $0x2F, %al
outb %al, $0x42
# nanosleep
movl $0x1000, %eax
1: subl $1, %eax
cmpl $0, %eax
jne 1b
movb $0x15, %al
outb %al, $0x42
# nanosleep
movl $0x1000, %eax
1: subl $1, %eax
cmpl $0, %eax
jne 1b
# turn on the speaker
inb $0x61, %al
movb %al, %ah
orb $0x3, %al
outb %al, $0x61
# sleep about 1 sec
movl $0x30000000, %eax
1: subl $1, %eax
cmpl $0, %eax
jne 1b
# turn off the speaker
movb %ah, %al
andb $0xfc, %al
outb %al, $0x61
This code won't work immediately in userspace program, because kernel forbids writing into IO ports. In order to allow that the code also requires ioperm call: ioperm(0x42, 32, 1) and running with sudo. See the full working example in this gist.
I am trying to add two 128 bits numbers using ATT assembly syntax in linux ubuntu 64b and I am debugging it in gdb so I know that after every loop the result of adding two parts is correct but how to store all 4 results together?? I was considering adding every result to the stack but I can't add the register content to the stack, right? Am I even doing it correctly? I am a real beginner in assembler but I need it for uni :/
EXIT_SUCCESS = 0
SYSEXIT = 1
number1:
.long 0x10304008, 0x701100FF, 0x45100020, 0x08570030
number2:
.long 0xF040500C, 0x00220026, 0x321000CB, 0x04520031
.global _start
_start:
movl $4, %edx
clc
pushf
_loop:
dec %edx
movl number1(,%edx,4), %eax
movl number2(,%edx,4), %ebx
popf
adcl %ebx, %eax
cmp $0, %edx
jne _loop
popf
jnc _end
push $1
_end:
mov $SYSEXIT, %eax
mov $EXIT_SUCCESS, %ebx
int $0x80
I have a quick ASM conversion question.
pop %ebx
xor %eax, %eax
movb %al, 7(%ebx)
movl %ebx, 8(%ebx)
movl %eax, 12(%ebx)
xor %eax, %eax
movb $11, %al
leal 8(%ebx), %ecx
leal 12(%ebx), %edx
int $0x80
My try:
pop ebx
xor eax, eax
mov [ebx+7], al
mov [ebx+8], ebx
mov [ebx+12], eax
xor eax, eax
mov al, 11
lea ecx, [ebx+8]
lea edx, [ebx+12]
int 80h
The main issue I'm having is the 7(%ebx) (and simmilar). Does it actually mean [ebx+7]?
It needs to allow a two-digit number for input that will be used to indicate how many times the name is printed. I can't figure out how to separate the second digit though and have it checked to make sure it is between 0x30 and 0x39. I also keep getting this weird box after the name that has 0017 inside it.
.data
input_msg_len: .long 26
input_msg: .ascii "Enter a two-digit number: "
name: .ascii "Michael Chabon\n"
name_len: .long 16
max: .long 0
count: .long 0
tmp: .long 0
input_str: .ascii "??"
.text
.global _start
_start:
mov $4, %eax
mov $1, %ebx
mov $input_msg, %ecx
mov input_msg_len, %edx
int $0x80
mov $3, %eax
mov $0, %ebx
mov $input_str, %ecx
mov $2, %edx
int $0x80
mov $input_str, %eax
add count, %eax
mov $input_str, %eax
mov (%eax), %bl
cmp $0x30, %bl
jl _start
cmp $0x39, %bl
jg _start
mov count, %eax
inc %eax
mov %eax, count
sub $0x30, %bl
mov %bl, max
mov $10, %bl
imul %bl
mov %bl, max
#Not sure how to check second char in input_str.
#Want to check it then subtract $0x30 and move to tmp before adding tmp to max.
mov $0, %edi
again:
cmp max, %edi
je end
mov $4, %eax
mov $1, %ebx
mov $name, %ecx
mov name_len, %edx
int $0x80
inc %edi
jmp again
end:
mov $1, %eax
int $0x80
Thanks in advance!
There are some bugs in your code.
Below, 2 first lines of that block are redundant, as mov $input_str, %eax overwrites eax anyway.
mov $input_str, %eax
add count, %eax
mov $input_str, %eax
Then here, it makes no sense to load count into eax here:
mov count, %eax
inc %eax
mov %eax, count
You can do this in a lot shorter and clearer way with:
incl count
Then, next bug is that you recently loaded count into eax, and then multiply the lowest 8 bits of count loaded into al with 10, in this piece of code:
mov (%eax), %bl // bl = first character
cmp $0x30, %bl
jl _start
cmp $0x39, %bl
jg _start
mov count, %eax // eax = count
inc %eax // eax++
mov %eax, count // count = eax
sub $0x30, %bl // 0 <= bl <= 9
mov %bl, max // max = bl <- you lose this value in the next mov %bl, max
mov $10, %bl // bl = 10
imul %bl // ax = 10 * and(count, 0xff) // ax = al*bl (signed multiply)
mov %bl, max // max = 10 <- here you overwrite the value of max with 10
So, according to my intuition you don't want to do ax = 10 * and(count, 0xff), but 10 * (first number). imul %bl does o signed multiply between al and bl, and stores the result in ax. So the code above could be changed to something like this:
mov (%eax), %bl // bl = first character
cmp $0x30, %bl
jl _start
cmp $0x39, %bl
jg _start
incl count
pushl %eax // push eax to stack
sub $0x30, %bl // 0 <= bl <= 9
mov $10, %al // al = 10
imul %bl // ax = 10 * bl (signed multiply)
mov %al, max // 0 <= max <= 90
Then, you can check the second character similarly to the first character:
pop %eax // pop eax from stack
incl %eax
mov (%eax), %bl // bl = second character
cmp $0x30, %bl
jl _start
cmp $0x39, %bl
jg _start
sub $0x30, %bl // 0 <= bl <= 9
add %bl, max // 0 <= max <= 99
I strongly recommend you to learn to use some debugger. gdb has several frontends, of which I think ddd works best according to my experience. gdbtui is also convenient.