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.
Related
I was writing this simple programm to calculate a ith element of a recursive sequence. The sequence basically looks like
a(n)=a(n-1)*a(n-2)
with first two elements being -1 and -3. I use imul for multiplying and due to my findings in the net I should be able to use any registers I want, but programm returns 0 for third element. When switched to add it works as intended.
Here's the fragment where I recursively call the function and multiply (as seen, I use stack to store my variables)
push %rcx
push %rax
call calculate
pop %rax
pop %rcx
imul %rcx, %rbx
Basically question is "why it doesn't work" :P
PS. In case full code is needed:
.data
STDOUT = 1
SYSWRITE = 1
HOW_MANY = 3 # which number to calculate
SYSEXIT = 60
EXIT_SUCCESS = 0
FIRST = -1 # first element of the sequence
SECOND = -3 # second element of the sequence
NUMBER_BEGIN = 0x30
OUTPUT_BASE = 10
NEW_LINE = '\n'
PLUS = '+'
MINUS = '-'
.bss
.comm textin, 512
.comm textout, 512
.comm text2, 512
.comm znak, 1
.text
.globl _start
_start:
#
# Calling function to calculate ith element
#
mov $HOW_MANY, %r8
sub $1, %r8
push %r8 # push r8 (function argument) to stack
call calculate # call function to calculate
add $8, %rsp # removing parameter from stack
# now we should've have result in rbx
#
mov $0, %r15 # Flaga znaku (domyślnie 0 = +)
cmp $0, %rbx
jge to_ascii # Pomiń jeśli liczba jest dodatnia
not %rbx # Odwrócenie bitów liczby i dodanie 1,
inc %rbx # aby uzyskać jej wartość bezwzględną.
mov $1, %r15 # Ustawienie flagi znaku na 1 = -.
to_ascii:
mov %rbx, %rax # result goes to rax
mov $OUTPUT_BASE, %rbx
mov $0, %rcx
jmp loop
loop:
mov $0, %rdx
div %rbx # divide rax by rbx, rest in rdx
add $NUMBER_BEGIN, %rdx # rest in rdx is a next position number
mov %dl, text2(, %rcx, 1)
inc %rcx
cmp $0, %rax
jne loop
jmp inverse
inverse:
mov $0, %rdi
mov %rcx, %rsi
dec %rsi
jmp inversev2
inversev2:
mov text2(, %rsi, 1), %rax
mov %rax, textout(, %rdi, 1)
inc %rdi
dec %rsi
cmp %rcx, %rdi
jle inversev2
push %rcx # legth of the answer goes to stack
mov $0, %r10 # want sign at the first position
movb $PLUS, znak(, %r10, 1)
cmp $0, %r15 # r15 register contains info about the sign
je next # 0 = +, so nothing has to be done
movb $MINUS, znak(, %r10, 1) # otherwise set it to minus
next: # show sign
mov $SYSWRITE, %rax
mov $STDOUT, %rdi
mov $znak, %rsi
mov $1, %rdx
syscall
pop %rcx
movb $NEW_LINE, textout(, %rcx, 1)
inc %rcx
mov $SYSWRITE, %rax
mov $STDOUT, %rdi
mov $textout, %rsi
mov %rcx, %rdx
syscall
mov $SYSEXIT, %rax
mov $EXIT_SUCCESS, %rdi
syscall
# recursive function calculating ith element of a given sequence
# sequence =
# n_1 = -1
# n_2 = -3
# n_i = n_(i-1)*n_(i-2)
calculate:
push %rbp # push rbp to stack to save it's value
mov %rsp, %rbp # now stack pointer is stored in rbp
sub $8, %rsp
mov 16(%rbp), %rax
cmp $1, %rax
jl first
je second
mov $0, %rcx
# wywołanie dla n_(i-1)
dec %rax
push %rcx
push %rax
call calculate
pop %rax
pop %rcx # przepisać na rejestry imula
imul %rcx, %rbx
# wywołanie dla n_(i-2)
dec %rax
push %rcx
push %rax
call calculate
pop %rax
pop %rcx
imul %rcx, %rbx
return:
mov %rcx, %rbx
mov %rbp, %rsp
pop %rbp
ret
first:
mov $FIRST, %rbx
mov %rbp, %rsp
pop %rbp
ret
second:
mov $SECOND, %rbx
mov %rbp, %rsp
pop %rbp
ret
You are seeding %rcx to zero, then multiplying into that, so you will always have a product of zero.
Perhaps you want to change
mov $0, %rcx
to
mov $1, %rcx
I think you also need to reverse the
imul %rcx, %rbx
to
imul %rbx, %rcx
(I'm not familiar with that flavor of assembler)
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.
I'm a beginner in Linux assembler and I have some questions. I'd like to read some characters from keyboard, convert it to value (I understand that this convertion should be from ASCII to decimal, right?), do some math (add, sub, multiply, whatever) and display the result in Terminal. How should I do that? I wrote some code but it probably doesn't make sense:
SYSEXIT = 1
EXIT_SUCC = 0
SYSWRITE = 4
SYSCALL = 0x80
SYSREAD = 3
.data
value: .space 5, 0
value_len: .long .-value
result: .long
result_len: .long .-result
.text
.global _start
_start:
movl $SYSREAD, %eax
movl $EXIT_SUCC, %ebx
movl $value, %ecx
movl value_len, %edx
int $SYSCALL
movl $0, %edx
movl value_len, %ecx
for:
movb value(, %edx, 1), %al
subb $48, %al
movb %al, result(, %edx, 1)
inc %edx
loop for
add $10, result
movl $0, %edx
movl result_len, %ecx
for1:
movb result(, %edx, 1), %al
add $48, %al
movb %al, result(, %edx, 1)
inc %edx
loop for1
movl $SYSWRITE, %eax
movl $SYSEXIT, %ebx
movl $result, %ecx
movl result_len, %edx
int $SYSCALL
movl $SYSEXIT, %eax
movl $EXIT_SUCC, %ebx
int $SYSCALL
I don't know if I should reserve memory by spaces? Or reading characters in loop?
How to convert it, to be able to make some math operation and then convert it to be able to display it?
I know that to get the value of ASCII char I should subtract 48, but what next?
I had an idea to multiply each bits by 2^k where k is 0,1,2...n it's good idea? If so, how to implement something like this?
As you can see I had a lot of questions, but I only need to someone show me how to do, what I am asking about. I saw some similar problems, but nothing like this in Linux.
Thank you in advance for the all information.
All the best.
At first reading and writing the console in Linux is by using the file functions with special console handles, that have always the same values: STDIN=0, STDOUT=1 and STDERR=2.
At second you will need some decent documentation about Linux system calls. Notice that the C-centric one (like "man") are not suitable, because C language does not use the system calls directly, but has wrappers that often change the arguments and the result values.
On the following site you can download an assembly-centric SDK for Linux, that contains the needed documentation and many examples and include files.
If you only need the help files, you can browse them online: Here
If the problem is the conversion from ASCII string to number and then back to string, here are two simple procedures that can do the job, if the requirements are not so big. The StrToNum is not so advanced, it simply convert decimal unsigned number:
; Arguments:
; esi - pointer to the string
; Return:
; CF=0
; eax - converted number
; edx - offset to the byte where convertion ended.
;
; CF=1 - the string contains invalid number.
;
StrToNum:
push ebx esi edi
xor ebx,ebx ; ebx will store our number
xor eax,eax
mov al,[esi]
cmp al,'0'
jb .error
cmp al,'9'
jbe .digit
jmp .error
.digit:
sub al,'0'
add ebx,eax
inc esi
mov al,[esi]
cmp al,'0'
jb .finish
cmp al,'9'
ja .finish
mov edx,ebx ; multiply ebx by 10
shl ebx,3
add ebx,edx
add ebx,edx
jmp .digit
.finish:
mov eax, ebx
mov edx, esi
clc
pop edi esi ebx
ret
.error:
stc
pop edi esi ebx
ret
NumToStr is pretty flexible. It converts number to a string in any radix and with sign:
;**********************************************************************************
; NumToStr converts the number in eax to the string in any radix approx. [2..26]
; Arguments:
; edi - pointer to the string buffer
; ecx - radix
; eax - number to convert.
; There is no parameter check, so be careful.
; returns: edi points to the end of a converted number
;**********************************************************************************
NumToStr:
test eax,eax
jns NumToStrU
neg eax
mov byte [edi],"-"
inc edi
NumToStrU:
cmp eax,ecx
jb .lessA
xor edx,edx
div ecx
push edx
call NumToStrU
pop eax
.lessA:
cmp al, 10
sbb al, 69h
das
stosb
ret
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]?
I'm trying to write a simple program that takes string from the keyboard, then prints it to the screen. So far I couldn't make it work.
Here's the code:
.section .rodata
output: .string "you entered %s\n"
input: .string "%s"
.text
.globl main
.type main, #function
main:
pushl %ebp
movl %esp, %ebp
subl $100, %esp
pushl $input
call scanf
movl %ebp, %esp
subl $100, %esp
pushl $output
call printf
xorl %eax, %eax
movl %ebp, %esp
popl %ebp
ret
When I execute it, the output is you entered (null) for any given input.
when I set the offset of subl $100, %esp command (the one before call print) to subl $104, %esp I get you entered %s, and when the offset is set to 108 I get you entered *gibberish*.
I feel like it's a game where I need to guess where scanf saved the string on the stack (why isn't it where it should be?).
I am using IA32 instruction set.
Any help would be greatly appreciated.
Basically there are 3 problems in your program:
subl $100, %esp
pushl $input
# Error 1:
# As Frank Kotler already wrote at this point
# only $input is stored on the stack; however
# the address of the buffer must also be on
# the stack (see Frank Kotler's comment)
call scanf
movl %ebp, %esp
# Error 2:
# Now the buffer is below ESP.
# Because interrupts use the kernel stack they
# will not overwrite the memory below ESP.
# However signals will destroy the memory below
# ESP!!
#
# Instead of the lines:
# movl %ebp, %esp
# subl $100, %esp
#
# You should use something like this:
# add $8, %esp
# or:
# lea -100(%ebp), %esp
#
subl $100, %esp
# Error 3:
# As for "scanf" the second argument
# is missing on the stack
pushl $output
call printf
[org 0x0100]
jmp start
;=======Data===================================
s1: db 'Enter String: $'
s2: db 'Reversed String:$'
linefeed: db 10, '$'
;=======Read string and store into stack=======
start: mov dx, s1
mov ah, 09h
int 21h
mov dx, linefeed
mov ah, 09h
int 21h
mov si,0
mov bx,0
again: mov ah, 01h
int 21h
cmp al,byte 0dh
je endread
Page 8 of 10
mov bl,al
push bx
inc si
cmp si,15
je endread
jmp again
endread: Push si
;=======Read from stack and print to screen=====
mov dx, linefeed
mov ah, 09h
int 21h
mov dx, s2
mov ah, 09h
int 21h
mov dx, linefeed
mov ah, 09h
int 21h
pop si
r1: pop bx
mov dl,bl
mov ah, 02h
int 21h
dec si
cmp si,0
jne r1
mov dx, linefeed
mov ah, 09h
int 21h
mov ax, 0x4c00 ;terminate program
int 21h