The program starts a normal execution, ignores the user input and then hits an segmentation fault. I'm very new to nasm so I don't have a clue on how to solve this issue so therefore I didn't try anything this version is an version with modules and is straight up coded by me.
Console:
****#****:~/ASM_PRJ$ vim exp2.asm
****#****:~/ASM_PRJ$ nasm -f elf64 -o test.o exp2.asm
****#****:~/ASM_PRJ$ ld test.o -o check
****#****:~/ASM_PRJ$ ./check
What is your name? Hello, Segmentation fault (core dumped)
****#****:~/ASM_PRJ$ vim exp2.asm
****#****:~/ASM_PRJ$ nasm -f elf64 -o test.o exp2.asm
****#****:~/ASM_PRJ$ ld test.o -o check
****#****:~/ASM_PRJ$ ./check
What is your name? Hello, Segmentation fault (core dumped)
****#****:~/ASM_PRJ$ echo $?
139
The source code is:
; -----------------------------------------
; -----------------------------------------
; -----------------------------------------
; -----------------Syscals-----------------
; -----------------------------------------
; -----------------------------------------
; -----------------------------------------
std_in equ 0 ; Standard Input (Console)
std_out equ 1 ; Standard Ausgabe (Console)
std_err equ 2 ;
sys_r equ 0 ; Lesen (Console)
sys_w equ 1 ; Schreiben (Console)
sys_exit equ 60 ; Syscall beenden (Console)
; -----------------------------------------
; -----------------------------------------
; -----------------------------------------
; -----------------------------------------
; -----------------------------------------
; -----------------------------------------
; -----------------------------------------
section .data
text1 db "What is your name? "
text2 db "Hello, "
section .bss
name resb 16
section .text
global _start
;programm beenden
%macro exit 0
mov rax, sys_exit
mov rdi, 0
syscall
%endmacro
;print line
; PARAM 1 = .data LABEL
%macro pline 1
mov rdi, %1
call %%strlen
mov rdx, rax
mov rax, 1
mov rdi, 1
mov rsi, %1
syscall
ret
;strlen --------------------------------------------------
%%strlen:
push rcx ; save and clear out counter
xor rcx, rcx
%%strlen_next:
cmp [rdi], byte 0 ; null byte yet?
jz %%strlen_null ; yes, get out
inc rcx ; char is ok, count it
inc rdi ; move to next char
jmp %%strlen_next ; reprocess
%%strlen_null:
mov rax, rcx ; rcx = length in rax
pop rcx ; restore rcx
ret ; get out
%endmacro
;
; PARAM 1 = .bss LABEL
; PARAM 2 = .bss Reservierte Bytes
%macro rline 2
mov rax, sys_r
mov rdi, std_in
mov rsi, %1
mov rdx, %2
syscall
ret
%endmacro
_start:
pline text1
rline name, 16
pline text2
pline name
exit
I would be very thankful for additional learning repositories and tips
My OS Spec: Linux **** 4.4.0-17763-Microsoft #864-Microsoft Thu Nov 07 15:22:00 PST 2019 x86_64 x86_64 x86_64 GNU/Linux
-- Solved By Michael --
Updated Source:
; -----------------------------------------
; -----------------------------------------
; -----------------------------------------
; -----------------Syscals-----------------
; -----------------------------------------
; -----------------------------------------
; -----------------------------------------
std_in equ 0 ; Standard Input (Console)
std_out equ 1 ; Standard Ausgabe (Console)
std_err equ 2 ;
sys_r equ 0 ; Lesen (Console)
sys_w equ 1 ; Schreiben (Console)
sys_exit equ 60 ; Syscall beenden (Console)
; -----------------------------------------
; -----------------------------------------
; -----------------------------------------
; -----------------------------------------
; -----------------------------------------
; -----------------------------------------
; -----------------------------------------
section .data
text1 db "What is your name? "
text2 db "Hello, "
section .bss
name resb 16
section .text
global _start
;programm beenden
%macro exit 0
mov rax, sys_exit
mov rdi, 0
syscall
%endmacro
%macro strlen 1
mov rdi, %1
%%strlen:
push rcx ; save and clear out counter
xor rcx, rcx
%%strlen_next:
cmp [rdi], byte 0 ; null byte yet?
jz %%strlen_null ; yes, get out
inc rcx ; char is ok, count it
inc rdi ; move to next char
jmp %%strlen_next ; reprocess
%%strlen_null:
mov rax, rcx ; rcx = length in rax
pop rcx ; restore rcx
%endmacro
; print line
; PARAM 1 = .data LABEL
%macro pline 1
strlen %1
mov rdx, rax
mov rax, sys_w
mov rdi, std_out
mov rsi, %1
syscall
%endmacro
;
; PARAM 1 = .bss LABEL
; PARAM 2 = .bss Reservierte Bytes
%macro rline 2
mov rax, sys_r ; get syscall
mov rdi, std_in ; get input
mov rsi, %1 ; Label
mov rdx, %2 ; Reservierte Bytes
syscall
%endmacro
_start:
pline text1
rline name, 16
pline text2
pline name
exit
Still having an issue where Hello gets printed before user input
Ive just forgotten to set the nullbytes for the strlen macro.
couldnt be solved without #Michael
section .data
text1 db "What is your name? ",0,10
text2 db "Hello, ",0,10
Related
I am trying to convert an input character to an output symbol in x86 assembly. As an example, if the user enters A I want the below to be output:
$
$ $
$$$$$
$ $
$ $
And for B:
$$$$
$ $
$$$$
$ $
$$$$
etc. My current method is to set up a string of 0's and 1's and then loop through and convert a 0 to a space and a 1 to a $. I use a b as a line break (i.e. new line) and an x as end of string.
My code below (just showing A run through to shorten code):
section .data
; constants
NULL equ 0
EXIT_SUCCESS equ 0
EXIT_FAIL equ 1
SYS_exit equ 60
SYS_read equ 0
SYS_write equ 1
STD_in equ 0
STD_out equ 1
; other
text1 db "Please enter an upper-case letter from A-E: ",0
errmsg db "Error: incorrect letter chosen.",0
sucmsg db "Success.",0
symA db "00100b01010b11111b10001b10001x ",0
space db " "
dollar db "$"
lbreak db "b"
lend db "x"
section .bss
; reserve space for user input
letter resb 1
section .text
global _start
_start:
; print question
mov rax, text1
call _printText
; get user input
; sys_read (0, latter, 1)
mov rax, SYS_read
mov rdi, STD_in
mov rsi, letter
mov rdx, 1
syscall
; dereference rsi
movzx rsi, byte [letter]
; jump conditionals
mov rdx, "A"
cmp rsi, rdx
je _printA
; default jump if no match
; print fail msg
mov rax, errmsg
call _printText
jmp _exitFail
_printA:
xor eax, eax
; sys_write (1, text, 1)
mov rax, symA
call _printText
call _printChar
jmp _exitSuccess
_exitFail:
; default error exit
; sys_exit (1)
mov rax, SYS_exit
mov rdi, EXIT_FAIL
syscall
_exitSuccess:
; print success msg
mov rax, sucmsg
call _printText
; sys_exit (0)
mov rax, SYS_exit
mov rdi, EXIT_SUCCESS
syscall
; functions
_printText:
push rax
mov rbx, 0
_ptLoop:
inc rax
inc rbx
mov cl, [rax]
cmp cl, 0
jne _ptLoop
mov rax, SYS_write
mov rdi, STD_out
pop rsi
mov rdx, rbx
syscall
ret
_printChar:
;push rax
mov rbx, 0
_pcLoop:
inc rax
inc rbx
mov cl, [rax]
; if 0
cmp cl, 0
je _movSpace
; if 1
cmp cl, 1
je _movSymbol
; if newline
cmp cl, lbreak
je _movNewLine
; if end
cmp cl, lend
je _endPrint
_movSpace:
mov rcx, space
loop _pcLoop
_movSymbol:
mov rcx, dollar
loop _pcLoop
_movNewLine:
mov rcx, "\n"
loop _pcLoop
_endPrint:
mov rax, SYS_write
mov rdi, STD_out
mov rsi, rcx
mov rdx, rbx
syscall
ret
Currently, I have tried to debug as I was getting Segmentation fault (core dumped) in the _printChar function, however, now with the above code I am unable to create the executable file as it is returning the below error:
(.text+0x10e): relocation truncated to fit: R_X86_64_8 against '.data'
(.text+0x113): relocation truncated to fit: R_X86_64_8 against '.data'
when trying to run the below command in terminal:
ld filename.o -o filename
Can anyone suggest anything to assist with code above to achieve the objective I am after?
I assume that you make your program with
nasm -f elf64 filename.asm -o filename.o -l filename.lst
ld filename.o -o filename
Linker reports a problem at .text+0xca, so you need to find in the "filename.lst" what instruction was generated at this offset 0xca in the .text section:
....
112 000000C3 80F901 cmp cl, 1
113 000000C6 7416 je _movSymbol
114 ; if newline
115 000000C8 80F9[78] cmp cl, lbreak
116 000000CB 741D je _movNewLine
117 ; if end
118 000000CD 80F9[79] cmp cl, lend
119 000000D0 741F je _endPrint
....
It's the cmp cl, lbreak. Looking at the definition lbreak db "b" it obvious that your instruction incorrectly tried to compare a byte-value in cl with the offset of variable lbreak in section .data, which happens to be 78. You probably intended to compare cl with the value "b" stored in memory, using cmp cl, [lbreak] or even better, with the immediate value: cmp cl,"b".
Also consider printing the big letter as one 0-terminated string, using a single _printText:
SECTION .data
BigA DB " $ ",10
DB " $ $ ",10
DB "$$$$$",10
DB "$ $",10
DB "$ $",10
DB 0
BigB DB "$$$$ ",10
DB "$ $",10
DB "$$$$ ",10
DB "$ $",10
DB "$$$$ ",10
DB 0
I made this program that open a image file and find a hidden message in the file. I have to print the message on the console.
i think the part where i open the file and search for the hidden message is right, but i don´t know for sure because i can´t print the output to confirm.
this is the code:
; Example program to demonstrate file I/O.
; This example will open/create a file, write some
; information to the file, and close the file.
; Note, the file name is hard-coded for this example.
; This example program will open a file, read the
; contents, and write the contents to the screen.
; This routine also provides some very simple examples
; regarding handling various errors on system services.
; -------------------------------------------------------
section .data
; -----
; Define standard constants.
LF equ 10 ; line feed
NULL equ 0 ; end of string
TRUE equ 1
FALSE equ 0
EXIT_SUCCESS equ 0 ; success code
STDIN equ 0 ; standard input
STDOUT equ 1 ; standard output
STDERR equ 2 ; standard error
SYS_write equ 1; write
SYS_read equ 0 ; read
SYS_open equ 2 ; file open
SYS_close equ 3 ; file close
SYS_exit equ 60 ; terminate
SYS_creat equ 85 ; file open/create
SYS_time equ 201 ; get time
O_CREAT equ 0x40
O_TRUNC equ 0x200
O_APPEND equ 0x400
O_RDONLY equ 000000q ; read only
O_WRONLY equ 000001q ; write only
S_IRUSR equ 00400q
S_IWUSR equ 00200q
S_IXUSR equ 00100q
; -----
; Variables/constants for main.
BUFF_SIZE equ 256
newLine db LF, NULL
db LF, LF, NULL
fileName dq 6
fileDesc dq 0
errMsgOpen db "Error opening the file.", LF, NULL
errMsgRead db "Error reading from the file.", LF, NULL
offset db 1
size db 1
; -------------------------------------------------------
section .bss
readBuffer: resb BUFF_SIZE
; -------------------------------------------------------
section .text
global _start
_start:
xor rax, rax
xor rcx, rcx
xor rdx, rdx
xor rbx, rbx
mov rbx, rsp
mov rax, qword [rbx+16]
mov [fileName], rax
xor rax, rax
push rsp
; Attempt to open file - Use system service for file open
openInputFile:
pop rax ; pop argc value - should be 2
cmp rax, 0x2
jne done
mov rax, SYS_open ; file open
mov rdi, fileName ; file name string
mov rsi, O_RDONLY ; read only access
syscall ; call the kernel
cmp rax, 0 ; check for success
jl errorOnOpen
mov qword [fileDesc], rax ; save descriptor
; -----
; Read from file.
;
mov rax, SYS_read
mov rdi, qword [fileDesc]
mov rsi, readBuffer
mov rdx, BUFF_SIZE
syscall
cmp rax, 0
jl errorOnRead
; -----
; Print the buffer.
; add the NULL for the print string
mov rax, qword [readBuffer+2] ;SSSS
mov qword [size], rax
mov rax, qword [readBuffer+10] ;OOOO
mov [offset], rax
mov rcx, 0
ler: ;ler um caracter
mov rbp, 0
xor rbx, rbx
xor rdx, rdx
lerloop:
inc rax
cmp rax, [size]
je errorOnRead
saltaQuartobyte:
inc ecx
cmp ecx, 4
jne continua
inc rax ;incremneta rax outra vez para saltar o quarto
cmp rax, [size]
je errorOnRead
mov ecx, 0
continua:
mov bl, byte [readBuffer+rax]
shl rdx, 1
shr rbx, 1
adc rdx, 0
inc rbp
cmp rbp, 7 ;fim do caracter ASCII, 0X 0XXX XXXX
jne lerloop
mov rdi, rdx
call printString ; imprime caracter ASCII
cmp rax, [size] ;comea o priximo
jne ler
; -----
; Close the file.
mov rax, SYS_close
mov rdi, qword [fileDesc]
syscall
jmp done
; -----
; Error on open.
errorOnOpen:
mov rdi, errMsgOpen
call printString
jmp done
; Error on read.
errorOnRead:
mov rdi, errMsgRead
call printString
jmp done
; -----
; program done.
done:
mov rax, SYS_exit
mov rdi, EXIT_SUCCESS
syscall
; **********************************************************
; Generic procedure to display a string to the screen.
global printString
printString:
push rbp
mov rbp, rsp
push rbp
; -----
; Call OS to output string.
mov rax, SYS_write ; code for write()
mov rsi, rdi ; addr of characters
mov rdi, STDOUT ; file descriptor
; count set above
syscall ; system call
; -----
; String printed, return to calling routine.
prtDone:
pop rbx
pop rbp
ret
this is my last attempt of the print but the program still don't print anything, and I don't understand why? or what's wrong?
A fundamental error
push rsp
; Attempt to open file - Use system service for file open
openInputFile:
pop rax ; pop argc value - should be 2
cmp rax, 0x2
jne done
mov rax, SYS_open ; file open
Your program starts with copying the stackpointer RSP to the accumulator RAX, and then compares to see if the value is 2, but when is the stackpointer ever going to be 2? And so, the program will always prematurely exit. No wonder that nothing gets printed.
A selection of other errors
offset db 1
size db 1
...
mov rax, qword [readBuffer+2] ;SSSS
mov qword [size], rax
mov rax, qword [readBuffer+10] ;OOOO
mov [offset], rax
You have reserved not enough room to store the qwords size and offset!
Better store them in the .bss section using resq:
section .bss
readBuffer: resb BUFF_SIZE
offset resq 1
size resq 1
mov rax, qword [readBuffer+2] ;SSSS
mov qword [size], rax
mov rax, qword [readBuffer+10] ;OOOO
mov [offset], rax
If the file is a .BMP (I'm considering those well-known offsets), then the size and offset fields are actually dwords. You would have to write instead (loading EAX automatically zero extends the value into RAX):
mov eax, [readBuffer+2] ;SSSS
mov [size], rax
mov eax, [readBuffer+10] ;OOOO
mov [offset], rax
printString:
push rbp
mov rbp, rsp
push rbp <<<<
...
pop rbx <<<<
pop rbp
ret
Because of the mismatch, you're destroying RBX on return.
The code that you used depends on calculating the length of the ASCIIZ string. You cannot just leave that out!
This is my code with commented explanations:
SECTION .data ; Section containing initialised data
EatMsg: db "Eat at Joe's!",10
EatLen: equ $-EatMsg
SECTION .bss ; Section containing uninitialized data
SECTION .text ; Section containing code
global _start ; Linker needs this to find the entry point!
_start:
nop ; This no-op keeps gdb happy...
mov rax,1 ; Code for Sys_write call
mov rdi, 1 ; Specify File Descriptor 1: Standard Output
mov rsi, EatMsg ; Pass offset of the message
mov rdx, EatLen ; Pass the length of the message
mov R9, [EatMsg] ; move the adresse of Msg into R9
syscall
mov rcx, 5
DoMore:
mov rax, 1 ; Code for Sys_write call
mov rdi, 1 ; Specify File Descriptor 1: Standard Output
mov rsi, EatMsg ; Pass offset of the message
mov rdx, EatLen ; Pass the length of the message
dec rcx
jnz DoMore
syscall ; Make kernel call
mov rax, 1 ; Code for exit
mov rdi, 0 ; Return a code of zero
syscall ; Make kernel call
I am making a calculator in assembly for practice. It is working fine except for when the answer is displayed, the new line character (0x0A) will not display. Instead there is a box with the numbers 0014 inside (Unicode probably). Am I doing something wrong?
bits 64 ; 64-bit (amd64) code
section .data
stdin: equ 0
stdout: equ 1
sys_read: equ 0
sys_write: equ 1
sys_exit: equ 60
l_out1: db "Simple Assembly Addition",0Ah,": "
l_len1: equ 27
l_out2: db ": "
l_len2: equ 2
l_out3: db "Answer is: "
l_len3: equ 11
section .bss
l_in1: resb 3 ; reserve 3 bytes (digits)
l_in2: resb 3 ; reserve 3 bytes (digits)
l_ans: resb 4 ; answer
section .text
global _start
_start:
mov rax,sys_write ; system call id
mov rdi,stdout ; descriptor
mov rsi,l_out1
mov rdx,l_len1
syscall
mov rax,sys_read ; system call id
mov rdi,stdin ; descriptor
mov rsi,l_in1
mov rdx,3 ; see .bss
syscall
mov rax,sys_write ; system call id
mov rdi,stdout ; descriptor
mov rsi,l_out2
mov rdx,l_len2
syscall
mov rax,sys_read ; system call id
mov rdi,stdin ; descriptor
mov rsi,l_in2
mov rdx,3
syscall
mov r8,[l_in1] ; copy l_in1 to rax
sub r8,"0"
mov r9,[l_in2] ; copy l_in2 to rax
sub r9,"0"
add r8,r9
add r8,"0" ; add 0 for ascii conversion
mov [l_ans],r8 ; store answer to address of l_ans
mov rax,sys_write ; system call id
mov rdi,stdout ; descriptor
mov rsi,l_out3
mov rdx,l_len3
syscall
mov rax,sys_write ; system call id
mov rdi,stdout ; descriptor
mov rsi,l_ans
mov rdx,4
syscall
mov rax,sys_write
mov rdi,stdout
mov rsi,0Ah
mov rdx,1
syscall
mov rax,sys_exit ; system call id
mov rdi,0 ; return 0
syscall
How come this program is not printing out to the screen, am I missing something on the INT 80 command?
section .bss
section .data
hello: db "Hello World",0xa ;10 is EOL
section .text
global _start
_start:
mov ecx, 0; ; int i = 0;
loop:
mov dl, byte [hello + ecx] ; while(data[i] != EOF) {
cmp dl, 0xa ;
je exit ;
mov ebx, ecx ; store conetents of i (ecx)
; Print single character
mov eax, 4 ; set sys_write syscall
mov ecx, byte [hello + ebx] ; ...
mov edx, 1 ; move one byte at a time
int 0x80 ;
inc ebx ; i++
mov ecx, ebx ; move ebx back to ecx
jmp loop ;
exit:
mov eax, 0x01 ; 0x01 = syscall for exit
int 0x80 ;
ADDITION
My Makefile:
sandbox: sandbox.o
ld -o sandbox sandbox.o
sandbox.o: sandbox.asm
nasm -f elf -g -F stabs sandbox.asm -l sandbox.lst
Modified Code:
section .bss
section .data
hello: db "Hello World",0xa ;10 is EOL
section .text
global _start
_start:
mov ecx, 0; ; int i = 0;
while:
mov dl, byte [hello + ecx] ; while(data[i] != EOF) {
cmp dl, 0xa ;
je exit ;
mov ebx, ecx ; store conetents of i (ecx)
; Print single character
mov eax, 4 ; set sys_write syscall
mov cl, byte [hello + ebx] ; ...
mov edx, 1 ; move one byte at a time
int 0x80 ;
inc ebx ; i++
mov ecx, ebx ; move ebx back to ecx
jmp while ;
exit:
mov eax, 0x01 ; 0x01 = syscall for exit
int 0x80 ;
One of the reasons it's not printing is because ebx is supposed to hold the value 1 to specify stdin, and another is because sys_write takes a pointer (the address of your string) as an argument, not an actual character value.
Anyway, let me show you a simpler way of structuring your program:
section .data
SYS_EXIT equ 1
SYS_WRITE equ 4
STDOUT equ 1
TRAP equ 0x80
NUL equ 0
hello: db "Hello World",0xA,NUL ; 0xA is linefeed, terminate with NUL
section .text
global _start
_start:
nop ; for good old gdb
mov ecx, hello ; ecx is the char* to be passed to sys_write
read:
cmp byte[ecx], NUL ; NUL indicates the end of the string
je exit ; if reached the NUL terminator, exit
; setup the registers for a sys_write call
mov eax, SYS_WRITE ; syscall number for sys_write
mov ebx, STDOUT ; print to stdout
mov edx, 1 ; write 1 char at a time
int TRAP; ; execute the syscall
inc ecx ; increment the pointer to the next char
jmp read ; loop back to read
exit:
mov eax, SYS_EXIT ; load the syscall number for sys_exit
mov ebx, 0 ; return a code of 0
int TRAP ; execute the syscall
It can be simpler to NUL terminate your string as I did, or you could also do $-hello to get it's length at compile time. I also set the registers up for sys_write at each iteration in the loop (as you do), since sys_write doesn't preserve all the registers.
I don't know how you got your code to assemble, but it doesn't assemble over here for a couple of very good reasons.
You cannot use loop as a label name because that name is reserved for the loop instruction.
Your line 20's instruction mov ecx, byte [hello + ebx] doesn't assemble either because the source and destination operands' sizes don't match (byte vs dword). Possible changes:
mov cl, byte [hello + ebx]
mov ecx, dword [hello + ebx]
movzx ecx, byte [hello + ebx]
Was the above not the actual code you had?