I am writing a compiler in attempt to switch my programming language from interpreted to compiled
this is the code my script generated:
section .bss
digitSpace resb 100
digitSpacePos resb 8
string_at_index_0 resb 12
string_at_index_0_len resb 4
section .data
section .text
global _start
_start:
mov rax, "Hello world"
mov [string_at_index_0], rax
mov byte [string_at_index_0_len], 13
mov rax, 1
mov rdi, 1
mov rsi, string_at_index_0
mov rdx, string_at_index_0_len
syscall
mov rax, 60
mov rdi, 0
syscall
when i run this code with nasm -f elf64 -o test.o test.asm i get this warning:
warning:character constant too long [-w+other]
can anyone help me with this , and also if anyone could suggest a better way to output a Hello world that would be helpful too!
mov rax, "Hello world"
RAX is an 64-bit (8 byte) register, you are trying to put 11 bytes into it.
Here is a simple hello world:
As can be seen you don't want to put the message inside the register, you want to put a pointer to the message into rsi.
section .data
msg: db "Hello World"
section .text
global _start
_start:
mov rax, 1 ; write function
mov rdi, 1 ; to stdout
mov rsi, msg ; pointer to message
mov rdx, 11 ; length of the message
syscall ; write
Ideally, your compiler should declare string literals in .data section and pass pointers to them when using them in functions.
Related
I am beginner at assembly language and I don't understand why the code#1 works and code#2 doesn't... Does anybody know how to help me?
I want to print a new line, so i have copied this code#1:
section .data
newline_char: db 10
section .text
global _start
print_newline:
mov rax, 1
mov rdi, 1
mov rsi, newline_char
mov rdx, 1
syscall
But if i try the code#2, it doesn't work and the newline is not printed:
; I have removed the newline_char from here
section .text
global _start
print_newline:
mov rax, 1
mov rdi, 1
mov rsi, 10 ; I tried to put immediatly in here and have already tested '0x0a' '0ah'
mov rdx, 1
syscall
Does anyone know what I am doing wrong?
I am completely new to the assembly thing and googling for several hours and searching on SO didn't clear things out so I came to ask here.
What I want to achieve:
[first second]: hello (stays on the screen for 1 second)
[second second]: world (hello disappeared and now we have `world` in place of it)
And this flow is in an infinite loop
In other words, I want my terminal's stdout to flicker(change) between hello and world without appending any newlines, writing strings or any other things, I just want the existing, already printed text to be replaced with some another text.
I have written the infinite loop that will print hello, then wait for a second, then print world, and wait for a second. I have also put this code in an infinite loop.
Here is the code I have as of now:
section .data
hello db "hello",10,0
world db "world",10,0
delay dq 1,0
section .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, hello
mov rdx, 6
syscall
mov rax, 35
mov rdi, delay
mov rsi, 0
syscall
mov rax, 1
mov rdi, 1
mov rsi, world
mov rdx, 6
syscall
mov rax, 35
mov rdi, delay
mov rsi, 0
syscall
call _start
Note that I use elf64 asm format and it is highly appreciated to suggest a solution in that format.
Print a \r carriage return (ASCII code 13) to put the cursor at the beginning of the line without scrolling the terminal the way \n line feed (ASCII 10) does.
Then you can overwrite the last thing you wrote. If it's shorter, you can print spaces after your visible characters to "erase" the later characters still there.
e.g. since both words are the same length you could do this:
section .rodata
hello db 13, "hello" ; `\rhello`
hello_len equ $ - hello
world db 13, "world"
world_len equ $ - world
Notice that , 0 is not needed in your data because you're passing these buffers to write not printf, so they don't need to be 0-terminated implicit-length C strings. You also don't need to hard-code mov rdx, 6, you can use mov rdx, hello_len with the assembler calculating that for you.
For the sleeping part, you can use the sleep libc function, but for raw system calls you'll have to use nanosleep. (Like you're already doing.)
For the looping, don't use call _start; use jmp. You don't want to push a return address; that would eventually stack overflow (after about 1 million seconds: 8MiB stack size limit and call pushes an 8-byte return address.)
Solved this using helpful guidance of Peter Cordes.
The working code looks like this:
section .data
hello db "hello",13,0
world db "world",13,0
delay dq 1,0
section .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, hello
mov rdx, 6
syscall
mov rax, 35
mov rdi, delay
mov rsi, 0
syscall
mov rax, 1
mov rdi, 1
mov rsi, world
mov rdx, 6
syscall
mov rax, 35
mov rdi, delay
mov rsi, 0
syscall
jmp _start
I'm still learning assembly so my question may be trivial.
I'm trying to write an echo program with syscall, in which I get a user input and give it as output on the next line.
section .text
global _start
_start:
mov rax,0
mov rdx, 13
syscall
mov rsi, rax
mov rdx, 13
mov rax, 1
syscall
mov rax, 60
mov rdi, 0
syscall
I'm assuming all you want to do is return the input to the output stream, so to do that you need to do a few things.
First, create a section .bss in your code. This is for initializing data. You will initialize a string with any name you want and do so with label resb sizeInBits. for demonstration it will be a 32 bit string called echo.
Extra note, the ';' character is used for comments similar to what // is in c++.
Example code
section .data
text db "Please enter something: " ;This is 24 characters long.
section .bss
echo resb 32 ;Reserve 32 bits (4 bytes) into string
section .text
global _start
_start:
call _printText
call _getInput
call _printInput
mov rax, 60 ;Exit code
mov rdi, 0 ;Exit with code 0
syscall
_getInput:
mov rax, 0 ;Set ID flag to SYS_READ
mov rdi, 0 ;Set first argument to standard input
; SYS_READ works as such
;SYS_READ(fileDescriptor, buffer, count)
;File descriptors are: 0 -> standard input, 1 -> standard output, 2 -> standard error
;The buffer is the location of the string to write
;And the count is how long the string is
mov rsi, echo ;Store the value of echo in rsi
mov rdx, 32 ;Due to echo being 32 bits, set rdx to 32.
syscall
ret ;Return to _start
_printText:
mov rax, 1
mov rdi, 1
mov rsi, text ;Set rsi to text so that it can display it.
mov rdx, 24 ;The length of text is 24 characters, and 24 bits.
syscall
ret ;Return to _start
_printInput:
mov rax, 1
mov rdi, 1
mov rsi, echo ;Set rsi to the value of echo
mov rdx, 32 ;Set rdx to 32 because echo reserved 32 bits
syscall
ret ;Return to _start
I've just started to learn assembler (2 days ago) for x86 arch (but I program on x86_64 see below). I want to read in 2 numbers and for that I use Linux system calls (64 bit system). Well I looked up the corresponding numbers for read/write in unitstd_64.h and seems to work. But one thing bothers me (first the code):
section .data
prompt1 db "Enter a number: ", 0
lenMsg equ $-prompt1
outmsg db "Entered: ", 0
lenOut equ $-outmsg
section .bss
input1 resd 1
input2 resd 1
segment .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, prompt1
mov rdx, lenMsg
syscall
;read input number 1
mov rax, 0
mov rdi, 2
mov rsi, input1
mov rdx, 1
syscall
;prompt another number
mov rax, 1
mov rdi, 1
mov rsi, prompt1
mov rdx, lenMsg
syscall
;read input number 1
mov rax, 0
mov rdi, 2
mov rsi, input2
mov rdx, 1
syscall
;exit correctly
mov rax, 60
mov rdi, 0
syscall
The program does the following:
Shows prompt1
Let the user enter a number
Shows prompt1 again
quits (should'nt it let the user enter a number instead of quitting?)
Why is the fourth syscall simply ignored? Thanks in advance.
edit:
I use nasm. Object file created with nasm -f elf64 bla.asm. Linked with ld -o bla bla.o
So basically I'm trying to write a hello world program in assembly. The program exits as it should but no string is printed along the way. There are no errors anywhere either. I suspect that I am declaring or using the string wrong somehow.
.intel_syntax noprefix
.data
msg:
.ascii "Hello World"
.text
.globl _start
_start:
mov eax, 4 #call write
mov ebx, 1 #output into stdout
mov ecx, msg #what to write
mov edx, 11 #length of what to write
int 0x80
mov eax, 1 #exit
mov ebx, 0
int 0x80
I have also tried replacing
mov ecx, msg
with
mov ecx, [msg]
but it doesn't seem to make a difference.
You need to use mov ecx, offset msg or lea ecx, msg.
Also make sure you are assembling as 32 bit code in case you are on a 64 bit system.