segmentation fault with assembler code [duplicate] - linux

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

Related

How do I print a cpu register to the screen? [duplicate]

This question already has answers here:
How to represent hex value such as FFFFFFBB in x86 assembly programming?
(4 answers)
Basic use of immediates vs. square brackets in YASM/NASM x86 assembly
(4 answers)
How do I print an integer in Assembly Level Programming without printf from the c library? (itoa, integer to decimal ASCII string)
(5 answers)
What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?
(1 answer)
Closed 7 months ago.
I think my loop is wrong and the r10 register is not printing to the screen.
section .data
section .bss
know resd 16
section .text
global _start
_start:
REDO:
inc r10
mov eax, 4
mov ebx, 1
mov know, r10
mov rcx, know ; i want to print the r10 register to screen
;mov edx, 10
int 0x80
mov rax, r10 ; here i want to compare
cmp rax, ffff ; if r10 has reached ffff in its inc
je END ; jump out of loop if ffff is reached
jmp REDO
END:
What am I doing wrong here; do I have to put r10 into a variable then put that in to rcx to
print it to screen; does je mean if rax equals ffff jump; do I have to put a x after ffffx
do I have to put a x after ffffx
If your 'ffff' is to be the hexadecimal representation of the number 65535, then write it as 0xFFFF, prepending the 0x hexadecimal prefix.
does je mean if rax equals ffff jump
The je mnemonic stands for JumpIfEqual. Your code will jump if rax equals 0xFFFF.
I think my loop is wrong ...
Good news: your loop is correct, but you could write it somewhat better:
For testing the loop termination condition where r10 equals 0xFFFF, you don't need to first copy r10 to rax.
And instead of exiting the loop on r10 == 0xFFFF, better continue the loop on r10 != 0xFFFF. It will save you from writing the extra unconditional jmp.
... and the r10 register is not printing to the screen
For NASM, an instruction like mov know, r10 makes no sense. In this instruction, know is merily an immediate number and it can't possibly be the destination of anything. You were trying to store the contents of the r10 register in the buffer pointed at by know. The correct instruction would be mov [know], r10 using the square brackets.
An instruction like mov rcx, know is fine since it moves an immediate number (the address of know) into the register. Immediates can be the source operand.
Displaying a number requires you to convert the binary value into a string of characters that represent decimal digits.
The following Q/A's explain the process:
Displaying numbers with DOS
How do I print an integer in Assembly Level Programming without printf from the c library?
The value in r10 seems small enough, that we should not use the 64-bit division and instead use the faster 32-bit division:
know resb 64
...
REDO: inc r10d
mov eax, r10d
mov ebx, know + 63 ; High up in the buffer
mov ecx, ebx
mov edi, 10 ; CONST
.more: xor edx, edx
div edi
add edx, '0' ; Remainder [0,9] -> ["0","9"]
mov [rcx], dl
dec ecx
test eax, eax
jnz .more
mov byte [rcx], ' ' ; Leading space
sub ebx, ecx ; Number of digits
lea edx, [rbx + 1] ; plus the leading space char
mov ebx, 1
mov eax, 4
int 0x80
cmp r10d, 0x0000FFFF
jne REDO
END:
The leading space was added so that the numbers are not sticking together in this long series of numbers.
My previous answer nasm linux x64 how do i find and cmp EOF to stop printing data from file to screen
already warned you about using int 0x80 in 64-bit code. Today you still use it; was anything not clear from the link that I gave you?
know resb 64
...
REDO: inc r12d
mov eax, r12d
mov rbx, know + 63 ; High up in the buffer
mov rsi, rbx
mov edi, 10 ; CONST
.more: xor edx, edx
div edi
add edx, '0' ; Remainder [0,9] -> ["0","9"]
mov [rsi], dl
dec rsi
test eax, eax
jnz .more
mov byte [rsi], ' ' ; Leading space
sub rbx, rsi ; Number of digits
lea edx, [rbx + 1] ; plus the leading space char
mov edi, 1
mov eax, 1
syscall
cmp r12d, 0x0000FFFF
jne REDO
END:

Decode base64 in nasm

[Link for output after decoding. ][1]The code starts off well and then goes bezerk and then comes back to normal. It is meant to convert base64 nasm into its original form. I turn the first byte received, in ASCII in the rax register, into Base64 to get the binary equivalent. Make room for two bits and then take the next byte in rbx and do the same thing. Then get the top two bits in rbx and add to the first byte to get the ASCII equivalent and save the result. I cannot treat the end of the file with = because of this issue.
Thanks for the help.
; Build using these commands:
; nasm -f elf64 -g -F dwarf decode.asm
; ld -o decode decode.o
%macro writeIt 0
add al,bl ; add bl to al because upper rbx contains the rest
mov byte[B64LIN+rcx-1],al ; move the equivalent into B64LIN
%endmacro
; ************************************************************************
;;; Note: This process does automatic conversion into ASCII ##############
; ************************************************************************
%macro clear 1
xor %1,%1
%endmacro
SECTION .bss ; Section containing uninitialized data
BUFFLEN equ 4
Buff: resb BUFFLEN
SECTION .data ; Section containing initialised data
B64LIN: db "000",0 ; used for output
B64LEN: EQU $-B64LIN ; only used to determine the size of the string treated
SECTION .text ; Section containing code
;;; We convert ASCII to Base 64
Base64:
.UpperCase: ; remove 65 to convert match the B64Table
sub rax,65
ret
.LowerCase: ; remove 71 to convert match the B64Table
sub rax,71
ret
.Numbers: ; add 4 for numbers
add rax,4
ret
.Addition: ; remove 62 to convert match the B64Table
sub rax,62
ret
.BackSlash: ; remove 63 to convert match the B64Table
sub rax,63
ret
;------------------------------------------------------------------------
; Encode: Enconde binary datas into Base 64
; UPDATED: 15/12/2017
; IN: File
; RETURNS: ASCII VERSION
; MODIFIES: ASCII to Base 64
;;; Behaves like a switch statement
;;; Look for the equivalent Base64
Convert:
cmp rax,61h
jge Base64.LowerCase
cmp rax,41h
jge Base64.UpperCase
cmp rax,3Dh
je .EOF1
cmp rax,30h
jge Base64.Numbers
cmp rax, 2Bh
je Base64.Addition
cmp rax,2Fh
je Base64.BackSlash
cmp rax,rbx ; comparing rbx to rax for zeros
je Exit ; we're done if that happens
; *****************************************************************************
;;; Note: This process doesn't send any values back because it was added to the
;;; file in the encoding process. ##############
; *****************************************************************************
.EOF1:
clear rax
writeIt
ret
;;; Register clean up
Decode:
;;; Treating 1st Byte
mov al,byte[Buff+rcx] ; takes in the first element in the input
call Convert ; convert to get their Base64 value
;;; Treating 2nd Byte
inc rcx ; increment to get the next element in the Buff
mov bl,byte[Buff+rcx] ; moves second element into rbx
xchg al,bl ; xchg rax with rbx because Convert deals with rax
call Convert ; call Convert to get the base64 equiv.
xchg bl,al ; get the values back and exchange them
rol rax,2 ; make room for the first 2 bits in rbx
ror rbx,4 ; keep only the top four since first 2 bits are 00
writeIt
clear bl ; clear bl so we can role back
rol rbx,8 ; role 8 so we already make room when we moves rax
;;; Treating 3rd Byte
inc rcx ; increment to get the next element
mov al,byte[Buff+rcx] ; moves it directly into al since previous element is gone
call Convert ; Converts to Base64
ror rax,2 ; roll right to get the top 4 bits only
xchg rax,rbx ; xchg so even the top bits are kept in the process
writeIt
;;; Treating 4th Byte
clear bl ; clear lower 4 bits
clear rax ; clears everything since we have no use for it
inc rcx ; increments to get next
mov al,byte[Buff+rcx] ; moves next Byte into al
call Convert ; converts to Base64 equiv.
rol rbx,8 ; make room for last 2 bits coming
writeIt
ret
;;; code keeps on running onto PrintLine to finish off
;-------------------------------------------------------------------------
; IN: Nothing
; RETURNS: The Original text
; MODIFIES: Nothing
; CALLS: Kernel sys_write
PrintLine:
push rax ; Save all used registers
push rbx ; Save all used registers
push rcx ; Save all used registers
push rdx ; Save all used registers
mov rax,4 ; Specify sys_write call
mov rbx,1 ; Specify File Descriptor 1: Standard output
mov rcx,B64LIN ; Pass offset of line string
mov rdx,B64LEN ; Pass size of the line string
int 80h ; Make kernel call to display line string
pop rdx ; Restore all caller's registers
pop rcx ; dito
pop rbx ; dito
pop rax ; dito
ret ; Return to caller
;-------------------------------------------------------------------------
LoadBuff:
push rax ; Save caller's EAX
push rbx ; Save caller's EBX
push rdx ; Save caller's EDX
mov rax,3 ; Specify sys_read call
mov rbx,0 ; Specify File Descriptor 0: Standard Input
mov rcx,Buff ; Pass offset of the buffer to read to
mov rdx,BUFFLEN ; Pass number of bytes to read at one pass
int 80h ; Call sys_read to fill the buffer
mov rbp, rax ; Save # of bytes read from file for later
xor rcx,rcx ; Clear buffer pointer ECX to 0
pop rdx ; Restore caller's EDX
pop rbx ; Restore caller's EBX
pop rax ; Restore caller's EAX
ret ; And return to caller
GLOBAL _start
; ------------------------------------------------------------------------
; MAIN PROGRAM BEGINS HERE
;-------------------------------------------------------------------------
_start:
; We will stay into this loop until the buffer is empty
Read:
call LoadBuff ; Read first buffer of data from stdin
cmp rbp,0 ; If ebp=0, sys_read reached EOF on stdin
jbe Exit ; If ebp=0, we jumps to Exit
call Decode ; If there's still some data into the buffer, we call Encode to convert them
call PrintLine ; Save the enconded data into stdout
clear rbp ; Clear ebp for the next LoadBuff
jmp Read ; Read one more time the data from stdi
; The programm did his job, we can exit
Exit:
xor rax, rax ; Clear rax
xor rbx, rbx ; Clear rbx
mov rax,1 ; Code for Exit Syscall
mov rbx,0 ; Return a code of zero
int 0x80 ; Make kernel call`
[1]: https://i.stack.imgur.com/bHJnI.jpg

x86-64 Bit Assembly Linux Input

I'm trying to input into my program... All it does is run through and print a '0' to the screen. I'm pretty sure that the PRINTDECI function works, I made it a while ago and it works. Do I just have to loop over the input code and only exit when I enter a certain value? I'm not sure how I would do that... Unless it's by ACSII values which might suck.... Anyways, here's my code (Yasm(nasm clone), Intel Syntax):
GLOBAL _start
SECTION .text
PRINTDECI:
LEA R9,[NUMBER + 18] ; last character of buffer
MOV R10,R9 ; copy the last character address
MOV RBX,10 ; base10 divisor
DIV_BY_10:
XOR RDX,RDX ; zero rdx for div
DIV RBX ; rax:rdx = rax / rbx
ADD RDX,0x30 ; convert binary digit to ascii
TEST RAX,RAX ; if rax == 0 exit DIV_BY_10
JZ CHECK_BUFFER
MOV byte [R9],DL ; save remainder
SUB R9,1 ; decrement the buffer address
JMP DIV_BY_10
CHECK_BUFFER:
MOV byte [R9],DL
SUB R9,1
CMP R9,R10 ; if the buffer has data print it
JNE PRINT_BUFFER
MOV byte [R9],'0' ; place the default zero into the empty buffer
SUB R9,1
PRINT_BUFFER:
ADD R9,1 ; address of last digit saved to buffer
SUB R10,R9 ; end address minus start address
ADD R10,1 ; R10 = length of number
MOV RAX,1 ; NR_write
MOV RDI,1 ; stdout
MOV RSI,R9 ; number buffer address
MOV RDX,R10 ; string length
SYSCALL
RET
_start:
MOV RCX, SCORE ;Input into Score
MOV RDX, SCORELEN
MOV RAX, 3
MOV RBX, 0
SYSCALL
MOV RAX, [SCORE]
PUSH RAX ;Print Score
CALL PRINTDECI
POP RAX
MOV RAX,60 ;Kill the Code
MOV RDI,0
SYSCALL
SECTION .bss
SCORE: RESQ 1
SCORELEN EQU $-SCORE
Thanks for any help!
- Kyle
As a side note, the pointer in RCX goes to a insanely large number according to DDD... So I'm thinking I have to get it to pause and wait for me to type, but I have no idea how to do that...
The 'setup' to call syscall 0 (READ) on x86_64 system is:
#xenon:~$ syscalls_lookup read
read:
rax = 0 (0x0)
rdi = unsigned int fd
rsi = char *buf
rdx = size_t count
So your _start code should be something like:
_start:
mov rax, 0 ; READ
mov rdi, 0 ; stdin
mov rsi, SCORE ; buffer
mov rdx, SCORELEN ; length
syscall
The register conventions and syscall numbers for x86_64 are COMPLETELY different than those for i386.
Some conceptual issues you seem to have:
READ does not do ANY interpretation on what you type, you seem to be expecting it to let you type a number (say, 57) and have it return the value 57. Nope. It'll return '5', '7', 'ENTER', 'GARBAGE'... Your SCORELEN is probably 8 (length of resq 1), so you'll read, AT MOST, 8 bytes. or Characters, if you wish to call them that. And unless you type the EOF char (^D), you'll need to type those 8 characters before the READ call will return to your code.
You have to convert the characters you receive into a value... You can do it the easy way and link with ATOI() in the C library, or write your own parser to convert the characters into a value by addition and multiplication (it's not hard, see code below).
Used below, here as a reference:
#xenon:~$ syscalls_lookup write
write:
rax = 1 (0x1)
rdi = unsigned int fd
rsi = const char *buf
rdx = size_t count
Ugh.... So many... I'll just rewrite bits:
global _start
section .text
PRINTDECI:
; input is in RAX
lea r9, [NUMBER + NUMBERLEN - 1 ] ; + space for \n
mov r10, r9 ; save end position for later
mov [r9], '\n' ; store \n at end
dec r9
mov rbx, 10 ; base10 divisor
DIV_BY_10:
xor rdx, rdx ; zero rdx for div
div rbx : rax = rdx:rax / rbx, rdx = remainder
or dl, 0x30 ; make REMAINDER a digit
mov [r9], dl
dec r9
or rax, rax
jnz DIV_BY_10
PRINT_BUFFER:
sub r10, r9 ; get length (r10 - r9)
inc r9 ; make r9 point to initial character
mov rax, 1 ; WRITE (1)
mov rdi, 1 ; stdout
mov rsi, r9 ; first character in buffer
mov rdx, r10 ; length
syscall
ret
MAKEVALUE:
; RAX points to buffer
mov r9, rax ; save pointer
xor rcx, rcx ; zero value storage
MAKELOOP:
mov al, [r9] ; get a character
or al, al ; set flags
jz MAKEDONE ; zero byte? we're done!
and rax, 0x0f ; strip off high nybble and zero rest of RAX (we're lazy!)
add rcx, rcx ; value = value * 2
mov rdx, rcx ; save it
add rcx, rcx ; value = value * 4
add rcx, rcx ; value = value * 8
add rcx, rdx ; value = value * 8 + value * 2 (== value * 10)
add rcx, rax ; add new digit
jmp MAKELOOP ; do it again
MAKEDONE:
mov rax, rcx ; put value in RAX to return
ret
_start:
mov rax, 0 ; READ (0)
mov rdi, 0 ; stdin
mov rsi, SCORE ; buffer
mov rdx, SCORELEN ; length
syscall
; RAX contains HOW MANY CHARS we read!
; -OR-, -1 to indicate error, really
; should check for that, but that's for
; you to do later... right? (if RAX==-1,
; you'll get a segfault, just so you know!)
add rax, SCORE ; get position of last byte
movb [rax], 0 ; force a terminator at end
mov rax, SCORE ; point to beginning of buffer
call MAKEVALUE ; convert from ASCII to a value
; RAX now should have the VALUE of the string of characters
; we input above. (well, hopefully, right?)
mov [VALUE], rax ; store it, because we can!
; it's stored... pretend it's later... we need value of VALUE!
mov rax, [VALUE] ; get the VALUE
call PRINTDECI ; convert and display value
; all done!
mov rax, 60 ; EXIT (60/0x3C)
mov rdi, 0 ; exit code = 0
syscall
section .bss
SCORE: resb 11 ; 10 chars + zero terminator
SCORELEN equ $-SCORE
NUMBER: resb 19 ; 18 chars + CR terminator
NUMBERLEN equ $-NUMBER
I'm going to say that this should work first time, it's off-the-cuff for me, haven't tested it, but it should be good. We read up to 10 chars, terminate it with a zero, convert to a value, then convert to ascii and write it out.
To be more proper, you should save registers to the stack in each subroutine, well, certain ones, and really, only if you're going to interface with libraries... doing things yourself lets you have all the freedom you want to play with the registers, you just have to remember what you put where!
Yes, someone is going to say "why didn't you just multiply by 10 instead of weird adding?" ... uh... because it's easier on the registers and I don't have to set it all up in rdx:rax. Besides, it's just as readable and understandable, especially with the comments. Roll with it! This isn't a competition, it's learning!
Machine code is fun! Gotta juggle all the eggs in your head though... no help from the compiler here!
Technically, you should check return result (RAX) of the syscalls for READ and WRITE, handle errors appropriately, yadda yadda yadda.... learn to use your debugger (gdb or whatever).
Hope this helps.

NASM addition program

I am a developer who uses high level languages, learning assembly language in my spare time. Please see the NASM program below:
section .data
section .bss
section .text
global main
main:
mov eax,21
mov ebx,9
add eax,ebx
mov ecx,eax
mov eax,4
mov ebx,1
mov edx,4
int 0x80
push ebp
mov ebp,esp
mov esp,ebp
pop ebp
ret
Here are the commands I use:
ian#ubuntu:~/Desktop/NASM/Program4$ nasm -f elf -o asm.o SystemCalls.asm
ian#ubuntu:~/Desktop/NASM/Program4$ gcc -o program asm.o
ian#ubuntu:~/Desktop/NASM/Program4$ ./program
I don't get any errors, however nothing is printed to the terminal. I used the following link to ensure the registers contained the correct values: http://docs.cs.up.ac.za/programming/asm/derick_tut/syscalls.html
You'll have to convert the integer value to a string to be able to print it with sys_write (syscall 4). The conversion could be done like this (untested):
; Converts the integer value in EAX to a string in
; decimal representation.
; Returns a pointer to the resulting string in EAX.
int_to_string:
mov byte [buffer+9],0 ; add a string terminator at the end of the buffer
lea esi,[buffer+9]
mov ebx,10 ; divisor
int_to_string_loop:
xor edx,edx ; clear edx prior to dividing edx:eax by ebx
div ebx ; EAX /= 10
add dl,'0' ; take the remainder of the division and convert it from 0..9 -> '0'..'9'
dec esi ; store it in the buffer
mov [esi],dl
test eax,eax
jnz int_to_string_loop ; repeat until EAX==0
mov eax,esi
ret
buffer: resb 10
programming in assembly requires a knowledge of ASCII codes and a some basic conversion routines. example: hexadecimal to decimal, decimal to hexadecimal are good routines to keep somewhere on some storage.
No registers can be printed as they are, you have to convert (a lot).
To be a bit more helpfull:
ASCII 0 prints nothing but some text editors (kate in kde linux) will show something on screen (a square or ...). In higher level language like C and C++ is it used to indicate NULL pointers and end of strings.
Usefull to calculate string lengths too.
10 is end of line. depending Linux or Windows there will be a carriage return (Linux) too or not (Windows/Dos).
13 is carriage return
1B is the ESC key (Linux users will now more about this)
255 is a hard return, I never knew why it is good for but it must have its purpose.
check http://www.asciitable.com/ for the entire list.
Convert the integer value to a string.
Here i have used macros pack and unpack to convert integers to string and macro unpack to do the vice-versa
%macro write 2
mov eax, 4
mov ebx, 1
mov ecx, %1
mov edx, %2
int 80h
%endmacro
%macro read 2
mov eax,3
mov ebx,0
mov ecx,%1
mov edx,%2
int 80h
%endmacro
%macro pack 3 ; 1-> string ,2->length ,3->variable
mov esi, %1
mov ebx,0
%%l1:
cmp byte [esi], 10
je %%exit
imul ebx,10
movzx edx,byte [esi]
sub edx,'0'
add ebx,edx
inc esi
jmp %%l1
%%exit:
mov [%3],ebx
%endmacro
%macro unpack 3 ; 1-> string ,2->length ,3->variable
mov esi, %1
mov ebx,0
movzx eax, byte[%3]
mov byte[%2],0
cmp eax, 0
jne %%l1
mov byte[%2],1
push eax
jmp %%exit2
%%l1:
mov ecx,10
mov edx,0
div ecx
add edx,'0'
push edx
inc byte[%2]
cmp eax, 0
je %%exit2
jmp %%l1
%%exit2:
movzx ecx,byte[%2]
%%l2:
pop edx
mov [esi],dl
inc esi
loop %%l2
%endmacro
section .data ; data section
msg1: db "First number : " ;
len1: equ $-msg1 ;
msg2: db "Second number : " ;
len2: equ $-msg2 ;
msg3: db "Sum : " ;
len3: equ $-msg3 ;
ln: db 10
lnl: equ $-ln
var1: resb 10
var2: resb 10
str1: resb 10
str2: resb 10
ans: resb 10
ansvar: resb 10
ansl: db ''
l1: db ''
l2: db ''
section.text ;code
global _start
_start:
write msg1,len1
read str1,10
pack str1,l1,var1
write msg2,len2
read str2,10
pack str2,l2,var2
mov al,[var1]
add al,[var2]
mov [ansvar],al
unpack ans,ansl,ansvar
write msg3,len3
write ans,10
write ln,lnl
mov ebx,0 ; exit code, 0=normal
mov eax,1 ; exit command to kernel
int 0x80 ; interrupt 80 hex, call kernel
To assembler, link and run:
nasm -f elf add.asm
ld -s -o add add.o
./add

How to print a number in assembly NASM?

Suppose that I have an integer number in a register, how can I print it? Can you show a simple example code?
I already know how to print a string such as "hello, world".
I'm developing on Linux.
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.
You have to convert it in a string; if you're talking about hex numbers it's pretty easy. Any number can be represented this way:
0xa31f = 0xf * 16^0 + 0x1 * 16^1 + 3 * 16^2 + 0xa * 16^3
So when you have this number you have to split it like I've shown then convert every "section" to its ASCII equivalent.
Getting the four parts is easily done with some bit magic, in particular with a right shift to move the part we're interested in in the first four bits then AND the result with 0xf to isolate it from the rest. Here's what I mean (soppose we want to take the 3):
0xa31f -> shift right by 8 = 0x00a3 -> AND with 0xf = 0x0003
Now that we have a single number we have to convert it into its ASCII value. If the number is smaller or equal than 9 we can just add 0's ASCII value (0x30), if it's greater than 9 we have to use a's ASCII value (0x61).
Here it is, now we just have to code it:
mov si, ??? ; si points to the target buffer
mov ax, 0a31fh ; ax contains the number we want to convert
mov bx, ax ; store a copy in bx
xor dx, dx ; dx will contain the result
mov cx, 3 ; cx's our counter
convert_loop:
mov ax, bx ; load the number into ax
and ax, 0fh ; we want the first 4 bits
cmp ax, 9h ; check what we should add
ja greater_than_9
add ax, 30h ; 0x30 ('0')
jmp converted
greater_than_9:
add ax, 61h ; or 0x61 ('a')
converted:
xchg al, ah ; put a null terminator after it
mov [si], ax ; (will be overwritten unless this
inc si ; is the last one)
shr bx, 4 ; get the next part
dec cx ; one less to do
jnz convert_loop
sub di, 4 ; di still points to the target buffer
PS: I know this is 16 bit code but I still use the old TASM :P
PPS: this is Intel syntax, converting to AT&T syntax isn't difficult though, look here.
Linux x86-64 with printf
main.asm
default rel ; make [rel format] the default, you always want this.
extern printf, exit ; NASM requires declarations of external symbols, unlike GAS
section .rodata
format db "%#x", 10, 0 ; C 0-terminated string: "%#x\n"
section .text
global main
main:
sub rsp, 8 ; re-align the stack to 16 before calling another function
; Call printf.
mov esi, 0x12345678 ; "%x" takes a 32-bit unsigned int
lea rdi, [rel format]
xor eax, eax ; AL=0 no FP args in XMM regs
call printf
; Return from main.
xor eax, eax
add rsp, 8
ret
GitHub upstream.
Then:
nasm -f elf64 -o main.o main.asm
gcc -no-pie -o main.out main.o
./main.out
Output:
0x12345678
Notes:
sub rsp, 8: How to write assembly language hello world program for 64 bit Mac OS X using printf?
xor eax, eax: Why is %eax zeroed before a call to printf?
-no-pie: plain call printf doesn't work in a PIE executable (-pie), the linker only automatically generates a PLT stub for old-style executables. Your options are:
call printf wrt ..plt to call through the PLT like traditional call printf
call [rel printf wrt ..got] to not use a PLT at all, like gcc -fno-plt.
Like GAS syntax call *printf#GOTPCREL(%rip).
Either of these are fine in a non-PIE executable as well, and don't cause any inefficiency unless you're statically linking libc. In which case call printf can resolve to a call rel32 directly to libc, because the offset from your code to the libc function would be known at static linking time.
See also: Can't call C standard library function on 64-bit Linux from assembly (yasm) code
If you want hex without the C library: Printing Hexadecimal Digits with Assembly
Tested on Ubuntu 18.10, NASM 2.13.03.
It depends on the architecture/environment you are using.
For instance, if I want to display a number on linux, the ASM code will be different from the one I would use on windows.
Edit:
You can refer to THIS for an example of conversion.
I'm relatively new to assembly, and this obviously is not the best solution,
but it's working. The main function is _iprint, it first checks whether the
number in eax is negative, and prints a minus sign if so, than it proceeds
by printing the individual numbers by calling the function _dprint for
every digit. The idea is the following, if we have 512 than it is equal to: 512 = (5 * 10 + 1) * 10 + 2 = Q * 10 + R, so we can found the last digit of a number by dividing it by 10, and
getting the reminder R, but if we do it in a loop than digits will be in a
reverse order, so we use the stack for pushing them, and after that when
writing them to stdout they are popped out in right order.
; Build : nasm -f elf -o baz.o baz.asm
; ld -m elf_i386 -o baz baz.o
section .bss
c: resb 1 ; character buffer
section .data
section .text
; writes an ascii character from eax to stdout
_cprint:
pushad ; push registers
mov [c], eax ; store ascii value at c
mov eax, 0x04 ; sys_write
mov ebx, 1 ; stdout
mov ecx, c ; copy c to ecx
mov edx, 1 ; one character
int 0x80 ; syscall
popad ; pop registers
ret ; bye
; writes a digit stored in eax to stdout
_dprint:
pushad ; push registers
add eax, '0' ; get digit's ascii code
mov [c], eax ; store it at c
mov eax, 0x04 ; sys_write
mov ebx, 1 ; stdout
mov ecx, c ; pass the address of c to ecx
mov edx, 1 ; one character
int 0x80 ; syscall
popad ; pop registers
ret ; bye
; now lets try to write a function which will write an integer
; number stored in eax in decimal at stdout
_iprint:
pushad ; push registers
cmp eax, 0 ; check if eax is negative
jge Pos ; if not proceed in the usual manner
push eax ; store eax
mov eax, '-' ; print minus sign
call _cprint ; call character printing function
pop eax ; restore eax
neg eax ; make eax positive
Pos:
mov ebx, 10 ; base
mov ecx, 1 ; number of digits counter
Cycle1:
mov edx, 0 ; set edx to zero before dividing otherwise the
; program gives an error: SIGFPE arithmetic exception
div ebx ; divide eax with ebx now eax holds the
; quotent and edx the reminder
push edx ; digits we have to write are in reverse order
cmp eax, 0 ; exit loop condition
jz EndLoop1 ; we are done
inc ecx ; increment number of digits counter
jmp Cycle1 ; loop back
EndLoop1:
; write the integer digits by poping them out from the stack
Cycle2:
pop eax ; pop up the digits we have stored
call _dprint ; and print them to stdout
dec ecx ; decrement number of digits counter
jz EndLoop2 ; if it's zero we are done
jmp Cycle2 ; loop back
EndLoop2:
popad ; pop registers
ret ; bye
global _start
_start:
nop ; gdb break point
mov eax, -345 ;
call _iprint ;
mov eax, 0x01 ; sys_exit
mov ebx, 0 ; error code
int 0x80 ; край
Because you didn't say about number representation I wrote the following code for unsigned number with any base(of course not too big), so you could use it:
BITS 32
global _start
section .text
_start:
mov eax, 762002099 ; unsigned number to print
mov ebx, 36 ; base to represent the number, do not set it too big
call print
;exit
mov eax, 1
xor ebx, ebx
int 0x80
print:
mov ecx, esp
sub esp, 36 ; reserve space for the number string, for base-2 it takes 33 bytes with new line, aligned by 4 bytes it takes 36 bytes.
mov edi, 1
dec ecx
mov [ecx], byte 10
print_loop:
xor edx, edx
div ebx
cmp dl, 9 ; if reminder>9 go to use_letter
jg use_letter
add dl, '0'
jmp after_use_letter
use_letter:
add dl, 'W' ; letters from 'a' to ... in ascii code
after_use_letter:
dec ecx
inc edi
mov [ecx],dl
test eax, eax
jnz print_loop
; system call to print, ecx is a pointer on the string
mov eax, 4 ; system call number (sys_write)
mov ebx, 1 ; file descriptor (stdout)
mov edx, edi ; length of the string
int 0x80
add esp, 36 ; release space for the number string
ret
It's not optimised for numbers with base of power of two and doesn't use printf from libc.
The function print outputs the number with a new line. The number string is formed on stack. Compile by nasm.
Output:
clockz
https://github.com/tigertv/stackoverflow-answers/tree/master/8194141-how-to-print-a-number-in-assembly-nasm

Resources