I am making a program where the user enters a number, and it prints out all the numbers from zero up to the number. It compiles fine, links fine, and returns no errors when it runs, and yet it prints out absolutely nothing. Here is the code:
SECTION .data
len EQU 32
SECTION .bss
other resd len
data resd len
SECTION .text
GLOBAL _start
_start:
nop
input: ; This section gets the integer from the user
mov eax, 3 ; }
mov ebx, 1 ; }
mov ecx, data ; } System_read call
mov edx, len ; }
int 80h ; }
mov ebp, 1
setup: ; This section sets up the registers ready for looping
mov [other], ebp
loop: ; This section loops, printing out from zero to the number given
mov eax, 4
mov ebx, 1
mov ecx, [other]
mov edx, len
int 80h
exit: ; Exits the program
mov eax, 1 ; }
mov ebx, 0 ; } System_exit call
int 80h ; }
When I step through it on KDBG, it returns a few errors; it receives an interrupt and a segmentation fault, although I can't tell where. I'm not sure why though, because when I run it in Geany, it returns a 0 value at the end and runs without error. Why does it not work?
Thanks in advance
NOTE: This code does not loop. It is not finished yet. All it should do here is print out the number 1.
When you go to print, you are calling mov ecx, [other]. This looks at the address that's stored in other and follows that address to get whatever is stored there. The problem is that this system call is expecting an address in ecx, not a value.
If you call mov ecx, other instead, then ecx will have the address of other and it will be able to go to that address and print what's there.
You have another problem here: when you print the number stored in other, it will translate it into the ascii value. So, for example, when you try to print a 1, instead of printing the number 1, it will print ascii 1 (which happens to be a start of heading character; nothing you want to print). Add '0' (the character '0') if you want to print numbers.
EDIT: One more thing, when you read, you are passing 1 into ebx. 1 is STDOUT. What you want is STDIN which is 0.
Related
I'm new at learning assembly x86. I have written a program that asks the user to enter a number and then checks if it's even or odd and then print a message to display this information.
The code works fine but it has one problem. It only works for 1 digit numbers:
; Ask the user to enter a number from the keyboard
; Check if this number is odd or even and display a message to say this
section .text
global _start ;must be declared for linker (gcc)
_start: ;tell linker entry point
;Display 'Please enter a number'
mov eax, 4 ; sys_write
mov ebx, 1 ; file descriptor: stdout
mov ecx, msg1 ; message to be print
mov edx, len1 ; message length
int 80h ; perform system call
;Enter the number from the keyboard
mov eax, 3 ; sys_read
mov ebx, 2 ; file descriptor: stdin
mov ecx, myvariable ; destination (memory address)
mov edx, 4 ; size of the the memory location in bytes
int 80h ; perform system call
;Convert the variable to a number and check if even or odd
mov eax, [myvariable]
sub eax, '0' ;eax now has the number value
and eax, 01H
jz isEven
;Display 'The entered number is odd'
mov eax, 4 ; sys_write
mov ebx, 1 ; file descriptor: stdout
mov ecx, msg2 ; message to be print
mov edx, len2 ; message length
int 80h
jmp outProg
isEven:
;Display 'The entered number is even'
mov eax, 4 ; sys_write
mov ebx, 1 ; file descriptor: stdout
mov ecx, msg3 ; message to be print
mov edx, len3 ; message length
int 80h
outProg:
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg1 db "Please enter a number: ", 0xA,0xD
len1 equ $- msg1
msg2 db "The entered number is odd", 0xA,0xD
len2 equ $- msg2
msg3 db "The entered number is even", 0xA,0xD
len3 equ $- msg3
segment .bss
myvariable resb 4
It does not work properly for numbers with more than 1 digit because it only takes in account the first byte(first digit) of the entered number so it only checks that. So I would need a way to find out how many digits(bytes) there are in the entered value that the user gives so I could do something like this:
;Convert the variable to a number and check if even or odd
mov eax, [myvariable+(number_of_digits-1)]
And only check eax which contains the last digit to see if it's even or odd.
Problem is I have no ideea how could I check how many bytes are in my number after the user has entered it.
I'm sure it's something very easy yet I have not been able to figure it out, nor have I found any solutions on how to do this on google. Please help me with this. Thank you!
You actually want movzx eax, byte [myvariable+(number_of_digits-1)] to only load 1 byte, not a dword. Or just directly test memory with test byte [...], 1. You can skip the sub because '0' is an even number; subtracting to convert from ASCII code to integer digit doesn't change the low bit.
But yes, you need least significant digit, the last (highest address) in printing / reading order.
A read system call returns the number of bytes read in EAX. (Or negative error code). This will include a newline if the user hit return, but not if the user redirected from a file that didn't end with a newline. (Or if they submitted input on a terminal using control-d after typing some digits). The most simple and robust way would be to simply loop looking for the first non-digit in the buffer.
But the "clever" / fun way would be to check if [mybuffer + eax - 1] is a digit, and if so use it. Otherwise check the previous byte. (Or just assume there's a newline and always check [mybuffer + eax - 2], the 2nd-last byte of what was read. (Or off the start of the buffer if the user just pressed return.)
(To efficiently check for an ASCII digit; sub al, '0' / cmp al, 9 / ja non_digit. See double condition checking in assembly / What is the idea behind ^= 32, that converts lowercase letters to upper and vice versa?)
Just for fun, here's a more compact version that always just checks the 2nd-last byte of the read() input. (It doesn't check for being a digit, and it reads outside the buffer for input lengths of 0 or 1, e.g. pressing control-D or return.) Also for read errors, e.g. redirect with strace ./oddeven <&- to close its stdin.
Note the interesting part:
; check if the low digit is even or odd
mov ecx, msg_even
mov edx, msg_odd ; these don't set flags and actually could be done after TEST
test byte [mybuf + eax - 2], 1 ; check the low bit of 2nd-last byte of the read input
cmovnz ecx, edx
;Display selected message
mov eax, 4 ; sys_write
mov ebx, 1 ; file descriptor: stdout
mov edx, msg_odd.len
int 80h ; write(1, digit&1 ? msg_odd : msg_even, msg_odd.len)
I used cmov, but a simple branch over a mov ecx, msg_odd would work. You don't need to duplicate the whole setup for the system call, just run it with the right pointer and length. (ECX and EDX values, and I padded the odd message with a space so I could use the same length for both.)
And this is a homebrewed static_assert(msg_odd.len == msg_even.len), using NASM's conditional directives (https://nasm.us/doc/nasmdoc4.html). It's not just a separate preprocessor like C has, it can use NASM numeric equ expressions.
%if msg_odd.len != msg_even.len
; homebrew assert with NASM preprocessor, since I chose to skip doing a 2nd cmov for the length
%warn we assume both messages have the same length
%endif
The full thing. I outside of the part shown above, I just tweaked comments to sometimes simplify when I thought it was too redundant, and used meaningful label names.
Also, I put .rodata and .bss at the top because NASM complained about referencing msg_odd.len before it was defined. (You previously had your strings in .data, but read-only data should generally go in .rodata, so the OS can share those pages between runs of the same program because they stay clean.)
Other fixes:
Linux/Unix uses 0xa line endings, \n not \n\r.
stdin is fd 0. 2 is stderr. (2 happens to work because terminal emulators normally run the shell with all 3 file descriptors referring to the same read+write open file description for the tty).
; Ask the user to enter a number from the keyboard
; Check if this number is odd or even and display a message to say this
section .rodata
msg_prompt db "Please enter a number: ", 0xA
.len equ $- msg_prompt
msg_odd db "The entered number is odd ", 0xA ; padded with a space for same length as even
.len equ $- msg_odd
msg_even db "The entered number is even", 0xA
.len equ $- msg_even
section .bss
mybuf resb 128
.len equ $ - mybuf
section .text
global _start
_start: ; ld defaults to starting at the top of the .text section, but exporting a symbol silences the warning and can make GDB work more easily.
; Display prompt
mov eax, 4 ; sys_write
mov ebx, 1 ; file descriptor: stdout
mov ecx, msg_prompt
mov edx, msg_prompt.len
int 80h ; perform system call
mov eax, 3 ; sys_read
xor ebx, ebx ; file descriptor: stdin
mov ecx, mybuf
mov edx, mybuf.len
int 80h ; read(0, mybuf, len)
; return value in EAX: negative for error, 0 for EOF, or positive byte count
; for this toy program, lets assume valid input ending with digit\n
; the newline will be at [mybuf + eax - 1]. The digit before that, at [mybuf + eax - 2].
; If the user just presses return, we'll access before the end of mybuf, and may segfault if it's at the start of a page.
; check if the low digit is even or odd
mov ecx, msg_even
mov edx, msg_odd ; these don't set flags and actually could be done after TEST
test byte [mybuf + eax - 2], 1 ; check the low bit of 2nd-last byte of the read input
cmovnz ecx, edx
;Display selected message
mov eax, 4 ; sys_write
mov ebx, 1 ; file descriptor: stdout
mov edx, msg_odd.len
int 80h ; write(1, digit&1 ? msg_odd : msg_even, msg_odd.len)
%if msg_odd.len != msg_even.len
; homebrew assert with NASM preprocessor, since I chose to skip doing a 2nd cmov for the length
%warning we assume both messages have the same length
%endif
mov eax, 1 ;system call number (sys_exit)
xor ebx, ebx
int 0x80 ; _exit(0)
assemble + link with nasm -felf32 oddeven.asm && ld -melf_i386 -o oddeven oddeven.o
section .data:
msg1: db "Hello 10 times!"
msglen1: equ $-msg1
section .text:
global _initial:
global _start:
global _end:
_initial:
mov cx,10
_start:
dec cx
mov ecx,msg1
mov edx,msglen1
mov eax,4
int 80h
cmp cx,0
jz _end
jmp _start
_end
mov eax,1
int 80h
Above code had to be produce "Hello 10 times" 10 times.But it getting go into infinite loop,and i couldn't understand why ?
i think cx register doesn't decrease or whatever else ?
You have a number of problems.
The default entry point for a Linux program is _start. Your program starts by executing at label _start not at initial so your loop counter isn't being initialized.
Section names do not have a : on the name, and neither do labels for the global1
You are missing a parameter for the SYS_Write system call. The 32-bit system calls are documented in a table:
You need to set EBX to a file descriptor. STDIN=0, STDOUT = 1, STDERR=2. You want to write to the console so you need to set EBX to 1 before calling Int 80h
You are clobbering one of the parameters (ECX) to the SYS_Write system call. CX and ECX are part of the same register. CX is the lower 16-bits of ECX. Changing CX changes ECX. You need to use some other register for the loop counter. ESI, EDI, and EBP are currently unused in your code. Change all occurrences of CX to the 32-bit register ESI.
Your code could look like:
section .data
msg1: db "Hello 10 times!", 10
; Add 10 on the end of the string for Line Feed
; so each message prints on separate line
msglen1 equ $-msg1
section .text
global _initial
global _start
global _end
_start:
mov esi, 10 ; Initialize loop counter
_msgloop:
dec esi ; Decrement loop counter
mov ebx, 1 ; File Descriptor 1 = Write to Standard Output (STDOUT)
mov ecx, msg1 ; Address of message to print
mov edx, msglen1 ; Length of message to print
mov eax, 4 ; SYS_Write system call = 4
int 80h
cmp esi, 0 ; Has the loop counter reached 0?
jz _end ; If it has then we are done
jmp _msgloop ; otherwise go back and print message again
_end:
mov eax,1 ; SYS_Exit system call
int 80h
You could have rewritten your loop this way:
section .data
msg1: db "Hello 10 times!", 10
; Add 10 on the end of the string for Line Feed
; so each message prints on separate line
msglen1 equ $-msg1
section .text
global _start
_start:
mov esi, 10 ; Initialize loop counter
.msgloop:
mov ebx, 1 ; File Descriptor 1 = Write to Standard Output (STDOUT)
mov ecx, msg1 ; Address of message to print
mov edx, msglen1 ; Length of message to print
mov eax, 4 ; SYS_Write system call = 4
int 80h
dec esi ; Decrement loop counter
jnz .msgloop ; If loop counter hasn't reached zero then print again
mov eax,1 ; SYS_Exit system call
int 80h
Footnotes:
1You don't need to make initial and end global since you aren't linking to any other object files. Those global lines can be removed.
You're trying to use the cx register for your loop count, while needing to use ecx as a parameter for your output. Since cx is the lower 16 bits of ecx, you clobber your loop count.
You need to either use some other register (that is not used during the system call) for you loop count, or store the count in a local variable on the stack.
This is the code I have and it works fine:
section .bss
bufflen equ 1024
buff: resb bufflen
whatread: resb 4
section .data
section .text
global main
main:
nop
read:
mov eax,3 ; Specify sys_read
mov ebx,0 ; Specify standard input
mov ecx,buff ; Where to read to...
mov edx,bufflen ; How long to read
int 80h ; Tell linux to do its magic
; Eax currently has the return value from linux system call..
add eax, 30h ; Convert number to ASCII digit
mov [whatread],eax ; Store how many bytes has been read to memory at loc **whatread**
mov eax,4 ; Specify sys_write
mov ebx,1 ; Specify standart output
mov ecx,whatread ; Get the address of whatread to ecx
mov edx,4 ; number of bytes to be written
int 80h ; Tell linux to do its work
mov eax, 1;
mov ebx, 0;
int 80h
Here is a simple run and output:
koray#koray-VirtualBox:~/asm/buffasm$ nasm -f elf -g -F dwarf buff.asm
koray#koray-VirtualBox:~/asm/buffasm$ gcc -o buff buff.o
koray#koray-VirtualBox:~/asm/buffasm$ ./buff
p
2koray#koray-VirtualBox:~/asm/buffasm$ ./buff
ppp
4koray#koray-VirtualBox:~/asm/buffasm$
My question is: What is with these 2 instructions:
mov [whatread],eax ; Store how many byte reads info to memory at loc whatread
mov ecx,whatread ; Get the address of whatread in ecx
Why the first one works with [] but the other one without?
When I try replacing the second line above with:
mov ecx,[whatread] ; Get the address of whatread in ecx
the executable will not run properly, it will not shown anything in the console.
Using brackets and not using brackets are basically two different things:
A bracket means that the value in the memory at the given address is meant.
An expression without a bracket means that the address (or value) itself is meant.
Examples:
mov ecx, 1234
Means: Write the value 1234 to the register ecx
mov ecx, [1234]
Means: Write the value that is stored in memory at address 1234 to the register ecx
mov [1234], ecx
Means: Write the value stored in ecx to the memory at address 1234
mov 1234, ecx
... makes no sense (in this syntax) because 1234 is a constant number which cannot be changed.
Linux "write" syscall (INT 80h, EAX=4) requires the address of the value to be written, not the value itself!
This is why you do not use brackets at this position!
Recently, I wrote a bit of assembly code that asks for the password and if the user enters the correct password as stored internally, it prints out "Correct!". Else, it prints out "Incorrect!".
Here is the code:
section .text
global _start
_start:
mov edx, len_whatis
mov ecx, whatis
mov ebx, 1
mov eax, 4
int 80h ; outputs: "What is the password?"
mov edx, 5 ; expect 5 bytes of input(so 4 numbers)
mov ecx, pass
mov ebx, 0
mov eax, 3
int 80h ; accepts intput and stores in pass
mov eax, [pass] ; move the pass variable into eax
sub eax, '0' ; change the ascii number in eax to a numerical number
mov ebx, [thepass] ; move the thepass variable into ebx
sub ebx, '0' ; change the ascii number in ebx to a numerical number
cmp eax, ebx ; compare the 2 numbers
je correct ; if they are equal, jump to correct
jmp incorrect ; if not, jump to incorrect
correct:
mov edx, len_corr
mov ecx, corr
mov ebx, 1
mov eax, 4
int 80h ; outputs: "Correct!"
mov ebx, 0
mov eax, 1
int 80h ; exits with status 0
incorrect:
mov edx, len_incor
mov ecx, incor
mov ebx, 1
mov eax, 4
int 80h ; outputs: "Incorrect!"
mov eax, 1
int 80h ; exits with status: 1
section .data
whatis db "What is the password?", 0xA
len_whatis equ $ - whatis
thepass db "12345"
corr db "Correct!", 0xA
len_corr equ $ - corr
incor db "Incorrect!", 0xA
len_incor equ $ - incor
section .bss
pass resb 5
Assemble:nasm -f elf password.s
Link:ld -m elf_i386 -s -o password password.o
(If you did try to assemble link and run this, you may notice that it checks the password incorrectly - ignore this. It is "off topic")
Then, I ran a test:
I ran the code with ./password
When I was prompted for the password, I typed in 123456, one more byte than the code expects
After I hit enter and the code exits, the terminal immediately tries to run a command 6
What is causing this behavior? Is it something to do with the assembler, or how my computer is reading the code?
EDIT:
And, when I run the code with 12345, the terminal prompts for a command twice when the program closes, as if someone just hit the enter button without entering a command.
You're only reading five bytes from standard input, so when you type 123456↵, your application ends up reading 12345 and leaving 6↵ in the buffer. That gets passed on to the shell.
If you want to read the whole line, use a larger buffer.
I am having issues with using shifts to multiply two numbers given by the user.
It asks the user to enter two integers and it is supposed to multiply them.
My program works well in asking for the integers, but when it gives the product it is an astronomical number no where near being correct.
Where am I going wrong? what register is it reading?
%include "asm_io.inc"
segment .data
message1 db "Enter a number: ", 0
message2 db "Enter another number: ", 0
message3 db "The product of these two numbers is: ", 0
segment .bss
input1 resd 1
input2 resd 1
segment .text
Global main
main:
enter 0,0
pusha
mov eax, message1 ; print out first message
call print_string
call read_int ; input first number
mov eax, [input1]
mov eax, message2 ; print out second message
call print_string
call read_int ; input second number
mov ebx, [input2]
cmp eax, 0 ; compares eax to zero
cmp ebx, 0 ; compares ebx to zero
jnz LOOP ;
LOOP:
shl eax, 1
dump_regs 1
mov eax, message3 ; print out product
call print_string
mov ebx, eax
call print_int
You are going wrong in pretty much everything besides asking for the numbers.
You are acting like read_int writes the read integer into input1 the first time it is called and into intput2 the second time. This is almost certainly not the case.
Even were that the case, you load the first number into eax and then immediately overwrite it with the address of message2.
Even if eax and ebx were loaded correctly with the input values, your code that is supposed to be multiplying the two is actually be doing something along the lines of "if the second number is non-zero, multiply eax by 2. Otherwise leave it alone."
Even were the loop arranged correctly, it would be multiplying eax by 2 to the power of ebx.
Then you overwrite this result with the address of message3 anyway, so none of that matters.
In the end, it is impossible to determine what register is getting printed from this code. Between this question and your other question, you seem to be expecting print_int to print any of eax, ebx, or ecx.
Ignoring the code you've posted, and looking strictly at how to multiply numbers (without using a multiply instruction), you do something like this:
mult proc
; multiplies eax by ebx and places result in edx:ecx
xor ecx, ecx
xor edx, edx
mul1:
test ebx, 1
jz mul2
add ecx, eax
adc edx, 0
mul2:
shr ebx, 1
shl eax, 1
test ebx, ebx
jnz mul1
done:
ret
mult endp