Output Data Register Value in Nasm

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



Leave a reply



Submit