This question already has answers here:
How to convert a binary integer number to a hex string?
(3 answers)
Closed 3 years ago.
I am trying to print address of variable in NASM x86 assembly. When I assemble this code it assembles fine, however when I run this code it prints two characters instead of the address.
section .bss
Address: RESB 4
section .data
variable db 1
section .text
global _start
_start:
mov eax , variable ; variable Address is stored in eax register
mov [Address] , dword eax ; move the value of eax to Address
mov eax , 4 ; write system call in linux
mov ebx , 1 ; stdout file descriptor
mov ecx , Address ; memory address to be printed.
mov edx , 4 ; 4 bytes to be print
int 0x80
mov eax , 1
int 0x80
screenshot:
You should just format the output as hex number. You can use printf from C for this purpose
extern printf
section .bss
Address: RESB 4
section .data
variable db 1
fmt db "0x%x", 10, 0 ; format string
section .text
global _start
_start:
mov eax , variable ; variable Address is stored in eax register
mov [Address] , dword eax ; move the value of eax to Address
push dword [Address] ; push value of Address
push dword fmt ; address of format string
call printf ; calling printf
add esp, 8 ; pop stack 2*4 bytes after passing two variables to printf
mov eax, 0 ; exit code 0
int 0x80
Related
This question already has answers here:
Hello, world in assembly language with Linux system calls?
(1 answer)
What happens if there is no exit system call in an assembly program?
(1 answer)
Closed 11 months ago.
This works but I don't know what the last section does. If I remove it the code segfaults, so I'm assuming it is somehow related to closing the file or handling memory allocation but as far as I am aware that what the 6 instruction is for.
section .data
msg db 'Hello, world!', 0xa
len equ $ - msg
outfile db 'test_file.txt', 0
section .text
global _start
_start:
; creating and opening
mov eax, 8 ; set instruction
mov ebx, outfile ; set file name
mov ecx, 544o ; set file permissions
int 0x80 ; make system call
; writing to file
mov ebx, eax ; move file descriptor from previous call
mov eax, 4 ; set instruction
mov ecx, msg ; set text
mov edx, len ; set number of bytes to read
int 0x80 ; make system call
; closing file
mov eax, 6 ; set instruction
int 0x80 ; make system call
; closing program?
mov eax,1
mov ebx,0
int 0x80
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.
I am doing a proj. in 64-bit NASM. I have to convert decimal to binary and binary to decimal.
I keep getting segmentation fault after debugging when i call printf.
extern printf
section .bss
decsave: resd 2 ; stores dec->bin conversion
binsave: resd 1
section .data ; preset constants, writeable
dec1: db '1','2','4','.','3','7','5',0
bin1: dq 01010110110101B ; 10101101.10101 note where binary point should be
ten: dq 10
debug: db "debug 124 is %ld", 10, 0
section .text ; instructions, code segment
global main ; for gcc standard linking
main: ; label
push rbp ; save rbp
;parse and convert integer portion of dec->bin
mov rax,0 ; accumulate value here
mov al,[dec1] ; get first ASCII digit
sub al,48 ; convert ASCII digit to binary
mov rbx,0 ; clear register (upper part)
mov bl,[dec1+1] ; get next ASCII digit
sub rbx,48 ; convert ASCII digit to binary
imul rax,10 ; ignore rdx
add rax,rbx ; increment accumulator
mov rbx,0
mov bl,[dec1+2]
sub rbx,48
imul rax,10
add rax,rbx
mov [decsave],rax ; save decimal portion
mov rdi, debug
mov rsi, [decsave]
mov rax,0
call printf
; return using c-style pops to return stack to correct position
; and registers to correct content
pop rbp
mov rax,0
ret ; return
; print the bits in decsave:
section .bss
abits: resb 17 ; 16 characters & zero terminator
section .data
fmts: db "%s",0
section .text
; shift decimal portion into abits as ascii
mov rax,[decsave] ; restore rax to dec. portion
mov rcx,8 ; for printing 1st 8 bits
loop3: mov rdx,0 ; clear rdx ready for a bit
shld rdx,rax,1 ; top bit of rax into rdx
add rdx,48 ; make it ASCII
mov [abits+rcx-1],dl ; store character
ror rax,1 ; next bit into top of rax
loop loop3 ; decrement rcx, jump non zero
mov byte [abits+7],'.' ; end of dec. portion string
mov byte [abits+8],0 ; end of "C" string
push qword abits ; string to print
push qword fmts ; "%s"
call printf
add rsp,8
mov rax,[decsave+16] ; increment to fractional portion
mov rcx,16 ; for printing 3 bits as required in the directions
loop4: mov rdx,0 ; clear rdx ready for a bit
shld rdx,rax,1 ; top bit of rax into rdx
add rdx,48 ; make it ASCII
mov [abits+rcx-1],dl ; store character
ror rax,1 ; next bit into top of rax
loop loop4 ; decrement rcx, jump non zero
mov byte [abits+3],10 ; end of "C" string at 3 places
mov byte [abits+4],0 ; end of "C" string
push qword abits ; string to print
push qword fmts ; "%s"
call printf
add rsp,8
Is there a any other way to get around it?
Thank you.
As Jester pointed out, if the vararg function is not using sse, then al must be zero. There is a bigger issue here:
With the x86-64 calling convention, parameters are not passed on the stack as they are for 32bit, but instead passed through registers. Which registers all depend on what OS your program is written for.
x86 calling conventions
Any good NASM/Intel Assembly programmers out there? If so, I have a question for you!
Every tutorial I can find online, shows the usage of "printf" for printing the actual value of ARGC to the screen (fd:/dev/stdout). Is it not possible to simply print it with sys_write() for example:
SEGMENT .data ; nothing here
SEGMENT .text ; sauce
global _start
_start:
pop ECX ; get ARGC value
mov EAX, 4 ; sys_write()
mov EBX, 1 ; /dev/stdout
mov EDX, 1 ; a single byte
int 0x80
mov EAX, 1 ; sys_exit()
mov EBX, 0 ; return 0
int 0x80
SEGMENT .bss ; nothing here
When I run this, I get no output at all. I have tried copying ESP into EBP and tried using byte[EBP+4], (i was told the brackets de-reference the memory address).
I can confirm that the value when compared to a constant, works. For instance,
this code works:
pop ebp ; put the first argument on the stack
mov ebp, esp ; make a copy
cmp byte[ebp+4],0x5 ; does it equal 5?
je _good ; goto _good, &good, good()
jne _bad ; goto _bad, &bad, bad()
When we "pop" the stack, we technically should get the full number of arguments, no? Oh, btw, I compile with:
nasm -f elf test.asm -o test.o
ld -o test test.o
not sure if that is relevant. Let me know if i need to provide more information, or format my code for readability.
At least 2 problems.
You need to pass a pointer to the thing you want to print.
You probably want to convert to text.
Something like this should work:
SEGMENT .text ; sauce
global _start
_start:
mov ecx, esp ; pointer to ARGC on stack
add byte [esp], '0' ; convert to text assuming single digit
mov EAX, 4 ; sys_write()
mov EBX, 1 ; /dev/stdout
mov EDX, 1 ; a single byte
int 0x80
mov EAX, 1 ; sys_exit()
mov EBX, 0 ; return 0
int 0x80
Everyone's comments where very helpful! I am honored that you all pitched in and helped! I have used #Jester's code,
SEGMENT .text ; sauce
global _start
_start:
mov ecx, esp ; pointer to ARGC on stack
add byte [esp], '0' ; convert to text assuming single digit
mov EAX, 4 ; sys_write()
mov EBX, 1 ; /dev/stdout
mov EDX, 1 ; a single byte
int 0x80
mov EAX, 1 ; sys_exit()
mov EBX, 0 ; return 0
int 0x80
Which works perfectly when compiled, linked and loaded. The sys_write() function requires a pointer, such like in the common "Hello World" example, the symbol "msg" is a pointer as seen in the code below.
SECTION .data ; initialized data
msg: db "Hello World!",0xa
SECTION .text ; workflow
global _start
_start:
mov EAX, 4
mov EBX, 1
mov ECX, msg ; a pointer!
So first, we move the stack pointer into the counter register, ECX, with the code,
mov ecx, esp ; ecx now contains a pointer!
and then convert it to a string by adding a '0' char to the value pointed to by ESP (which is ARGC), by de-referencing it with square brackets, as [ESP] like so,
add byte[esp], '0' ; update the value stored at "esp"
Again, thank you all for the great help! <3
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!