Output Data Register value in NASM
First, thanks for the question-- it motivated me to study up in int 80h, something I wasn't familiar with before.
What does your program do in its current form? Does it print anything? If I'm executing it correctly in my head, I expect it to print the first message and then crash. Due to buffering, it might not even show the first message before the suspected crash.
int 80h/eax=4 maps to the write() function. Run 'man 2 write' to get the full documentation. The function prototype is:
ssize_t write(int fd, const void *buf, size_t count);
So, eax = 4, ebx = fd, ecx = buf, edx = count. If you want to be more pedantic with your code comments, "mov eax,4" means "write a string to a file" while "mov ebx,1" means "specify file #1, which maps to STDOUT (the terminal)".
I expect the first int 80h call to print something. The second int 80h call is suspect. At this point eax and ebx are unchanged. However, edx is also unchanged and that holds the string length of the first string. More problematic is that you are putting the value 5 into ecx. ecx holds a pointer to the string to be written, not a value to be written. So when you put 5 in there and call the interrupt, the int will try to print a string starting at address 0x00000005. This is almost certain to cause a segfault (crash).
Also, if I'm reading the int 80h docs correctly, the push/pop stack ops in your example don't have any relevance.
Printing a number as a string is a bit of a chore in ASM. You need to convert the number into a string and then you can print it using int 80h. Here's a way you can cheat if you just want to print a single digit:
- in the .data section, declare a new byte called int2char: 'int2char: db 0'
- after subtracting 5 from ecx, convert the digit to ASCII by adding 48 (this will give you '5' instead of 5)
- store ecx into int2char
- move the address of int2char into ecx
- set edx to 1 since you only want to print 1 char
Converting numbers with more than one digit will be left as an exercise for you once you get this working.
Good luck!
How to move value from .data to register in NASM?
In comments, Michael answered on my question, changing dw to dd solved the problem.
Moving contents from .data section to register in NASM
The OS X NASM 2.11.08 bug strikes again. Use an older version (like 2.11.06), or a newer version with a fix for relative symbol addressing in the data section. Or use yasm
.
Like I said in comments, you can zero a 64bit register with xor eax, eax
. That's the standard idiom.
Writing to a 32bit reg always clears the upper32 of the 64bit register. This saves a lot of instruction bytes compared to moving a 64bit immediate.
mov qword rax, 25
Is still a 32bit immediate move. The qword
is unnecessary. The instruction does have an unneeded REX prefix to make it a 64bit write, instead of just automatically clearing the high 32 by writing the low 32.
mov eax, 25
does the same thing, but with fewer instruction bytes.
How do I move the VALUE in a register to a memory variable in NASM?
Well, for a start, the value of rdi
is actually rdi
rather than [rdi]
. The latter, even assuming it's valid (I'm more of a gas
man than a nasm
man), would be the value stored in the memory that rdi
points to.
And, to specify sizes of operands (where gas
uses the more succinct movl/movb/etc
operations), you specify the size with the operands, such as:
mov qword [regValue], 9393
However, I don't think that's necessary when you're using a 64-bit register like rdi
for the source since the size can be inferred from that. I think you can just do:
mov [regValue], rdi
BTW, in NASM you should use default rel
at the top of your file to prefer RIP-relative addressing modes for static data (like [regValue]
), instead of 32-bit absolute.
NASM adding value to register bug
I have an idea - I'm not sure if it is correct:
In your program you call "open" two times. One time you commented out the mov ecx, ...
; the other time the ecx
register has never been set at all:
openFileIn:
mov eax, 5
mov ebx, fileName
; <-- Here you are trusting Linux that ecx=0 on program start
; This is not guaranteed;
; it may change in future Linux versions!
mov edx, 0777
int 0x80
mov [fd_in], eax
ret
openFileOut:
mov eax, 5
mov ebx, outName
;mov ecx, 1 <-- why did you comment this out?
; Maybe "1" is not the correct value!
mov edx, 0777
int 0x80
In anoter line you write some address to the ecx
register:
readFromFileIn:
mov eax, 3
mov ebx, [fd_in]
mov ecx, info ; <-- Here
mov edx, IMAGE_SIZE
int 0x80
ret
When you add instructions to your code the addresses of elements in the program may change - including the address of info
.
I suspect that without the additional instruction the address of info
is a valid parameter for the "open" system call by chance while after inserting the instruction the address is no longer a valid parameter for "open".
You could test this by running both variants of the program with the strace
tool which shows you which system calls are called with wich parameters.
How to change variable value in x86_64 assembly (nasm)
The thing you call a variable is a label that basically holds the address of the value in memory. When you want to change the value you need to use brackets []
and dereference the address that points to that location. Then you can change the values one by one. For example, lets define a one-byte variable:
v: db 0x00
To change the value you can do
mov byte[v], 0x02
As you can see we specified the size with byte
If we had the following variable:
abc: dw 0x0000
the variable abc
would only hold the address of the first byte of the data but the data itself is a word (2 bytes). That is why to change the variable's value we need to do:
mov word[abc], 0xDEAD
which would be equivalent to
mov byte[abc], 0xAD
mov byte[abc+1], 0xDE
Note that the least first byte of the 2-byte value is in the earlier memory address, this is called little-endian order.
A string is essentially a bunch of "bytes" next to each other (it doesn't use little endian). To change a string value one by one you can do:
text: db "Hello World", 0
mov byte [text], 'A' ; Aello World
mov byte [text+1], 'B' ; ABllo World
mov byte [text+2], 'C' ; ABClo World
; and etc
Also finally we can take a look at your code:
text db "Hello, World!",10
mov rax , "He"
mov [text], rax
syscall
This is not valid (as pointed out by @vitsoft) because you are putting "He"
inside of rax
before calling syscall
which uses rax
to determine what it's gonna do.
As a matter of fact this line of code
mov word [text], "He"
is perfectly valid. I don't know why you couldn't get that to work. "He"
is essentially resolved to 0x6548
and you do a normal mov
as a word. As I mentioned before because of the little-endian order for words, 0x48 ('H')
will be placed in the first byte of text
which is already "H"
and similarly 0x65 ('e')
will be placed in the second byte of text
which is already "e"
.
Edit:
Lets say you don't know the length of a string which you want to copy to another string/location. In that case you should loop over that string and do the changes one by one. I will leave a sample code here which you would need to fix and adapt:
start:
xor ecx, ecx ; initialize some variable to keep count
.loop:
mov al, byte [other + rcx] ; get the nth character of other.
cmp al, 0x00 ; if we reached the end of the string
je endLoop ; end the function
mov [text + rcx], al ; write the nth character of other to nth position of text
inc ecx ; increase counter
jmp .loop ; loop
endLoop:
ret
text: db "Hello World", 0
other: db "ABC", 0
How to print a number in assembly NASM?
If you're already on Linux, there's no need to do the conversion yourself. Just use printf instead:
;
; assemble and link with:
; nasm -f elf printf-test.asm && gcc -m32 -o printf-test printf-test.o
;
section .text
global main
extern printf
main:
mov eax, 0xDEADBEEF
push eax
push message
call printf
add esp, 8
ret
message db "Register = %08X", 10, 0
Note that printf
uses the cdecl calling convention so we need to restore the stack pointer afterwards, i.e. add 4 bytes per parameter passed to the function.
Related Topics
On Building Docker Image Level=Error Msg="Can't Close Tar Writer: Io: Read/Write on Closed Pipe"
How to Edit a Symlink with a Text Editor
How to Create a File Listener in Linux
Where Is Default Installation Directory for Mongodb
What Does It Mean to Break User Space
How to Avoid Grub Errors After Running Apt-Get Upgrade - Ubuntu
How Does Copy-On-Write in Fork() Handle Multiple Fork
Does There Exist Kernel Stack for Each Process
Powershell Connecting from a Linux Client to a Windows Remote
Can Tmux Save Commands to a File, Like .Bash_History
How to Test My Bash Script on Older Versions of Bash
How to Setup Cron Job on Amazon Linux Ami
How to Disable Tcp Slow Start in Linux
Replace Forward Slash with Double Backslash Enclosed in Double Quotes
Safer Alternative to Matlab's 'system' Command
Individual Thread Priority Checking Using Command Line in Linux
How Is Preemptive Scheduling Implemented for User-Level Threads in Linux
How Existing Kernel Driver Should Be Initialized as Pci Memory-Mapped