Reputation: 197
I have large 64 bit number stored in EDX:EAX as 21C3677C:82B40000 respectively. I'm trying to print the number out to the console as a decimal 2432902008176640000 Is there a system call that will allow me to accomplish this?
Upvotes: 1
Views: 3458
Reputation: 11
Here is an example how to print the 64 bit number with printf. This code works with YASM.
segment .data
format db "Number %ld", 0x0a, 0 ; Format string for printf
result dq 0 ; Quad word to store the EDX:EAX result in
segment .text
global main
extern printf
main:
; Store the 64 bit number in the quad word "result"
mov edx, 0x21C3677C ; Store the EDX value
mov eax, 0x82B40000 ; Store the EAX value
mov [result], eax ; Lower half of "result" will be EAX
mov [result+4], edx ; Upper half of "result" will be EDX
; Print "result" with the printf function
xor eax, eax ; No float parameters for printf
lea rdi, [format] ; First parameter for printf (format string)
mov rsi, [result] ; Second parameter for printf ("result")
call printf ; Call printf
; End program
xor eax, eax ; Return 0
ret
Build the binary with the following commands:
yasm -f elf64 example.asm
gcc -o example example.o
Update: Example without using memory
segment .data
format db "Number %ld", 0x0a, 0 ; Format string for printf
segment .text
global main
extern printf
main:
; Store the 64 bit number in register rsi
mov edx, 0x21C3677C ; Store the EDX value (upper half)
mov eax, 0x82B40000 ; Store the EAX value (lower half)
mov esi, edx ; Place upper half in esi
shl rsi, 32 ; Shift left 32 bits
or rsi, rax ; Place the lower half in rsi
; Print "result" with the printf function
xor eax, eax ; No float parameters for printf
lea rdi, [format] ; First parameter for printf (format string)
call printf ; Call printf
; End program
xor eax, eax ; Return 0
ret
Upvotes: 1
Reputation: 3119
Someone has to have mercy on this guy and his classmates. If "just call printf" isn't cheating, using this shouldn't be cheating either. I stole this from one of the first asm programs I ever encountered. It used a DOS interrupt to find the disk size and printed dx:ax
with commas every three digits. You guys probably don't need the commas. I've tinkered with it for years - probably do an rdx:rax
version sometime soon. Great for displaying factorials. It is very naive and inefficient, but still works. Feel free to improve it. After you've got the characters in the buffer, of course, it's just "Hello World" with different lyrics.
;----------------------------------------------- ; u64toda - converts (64 bit) integer in edx:eax ; to (comma delimited) decimal representation in ; zero (was "$") terminated string in buffer pointed to by edi ;---------------------------------------- u64toda: pusha mov ebx, edx ; stash high dword mov esi,0Ah ; prepare to divide by 10 xor ecx, ecx ; zero the digit count jmp highleft ; check is high word 0 ? highword: xchg eax,ebx ; swap high & low words xor edx,edx ; zero edx for the divide! div esi ; divide high word by 10 xchg eax,ebx ; swap 'em back div esi ; divide low word including remainder push edx ; remainder is our digit - save it inc ecx ; count digits highleft: or ebx,ebx jnz highword lowleft: xor edx,edx ; zero high word div esi ; divide low word by 10 push edx ; our digit inc ecx ; count it or eax,eax ; 0 yet ? jne lowleft cmp ecx, byte 4 ; commas needed ? jl write2buf ; nope xor edx,edx ; zero high word for divide mov eax,ecx ; number of digits mov ebx,3 div ebx mov esi,edx ; remainder = number digits before comma test edx,edx jnz write2buf ; no remainder? mov esi,3 ; we can write 3 digits, then. write2buf: pop eax ; get digit back - in right order add al,30H ; convert to ascii character stosb ; write it to our buffer dec esi ; digits before comma needed jnz moredigits ; no comma needed yet cmp ecx,2 ; we at the end? jl moredigits ; don't need comma mov al,',' ; write a comma stosb mov esi,03h ; we're good for another 3 digits moredigits: loop write2buf ; write more digits - cx of 'em mov al,00h ; terminate buffer with zero stosb popa ret ;------------------------
Upvotes: 1
Reputation: 11582
Which operating system? On linux you use the write
system call. This is the kind of thing that is done through standard libraries for the language you are using. You'll have to do the conversion from binary to decimal ASCII characters yourself, then point the write
system call to that ASCII text, give it the length, and tell it which file descriptor to write to, stdout would be file descriptor 1
.
Here's one way of finding out what system call is used in Linux. Write a simple program and invoke it under strace
, that will trace all system calls the program makes.
For example, I wrote this C++ program
#include <iostream>
int main( int argc, char* argv[] )
{
static volatile unsigned long long x = 0x21C3677C82B40000;
std::cout << x << std::endl;
return 0;
}
Compiled it as follows:
g++ -O3 main.cpp -o main
Then ran it with strace
redirecting stderr to a file main.trace
$ strace -y ./main 2> main.trace
2432902008176640000
$
It wrote the decimal number you expected. Look for I/O to a device by grep'ing for "dev" in the trace
$ grep dev main.trace
fstat(1</dev/pts/3>, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 3), ...}) = 0
write(1</dev/pts/3>, "2432902008176640000\n", 20) = 20
$
You'll notice the C++ standard library did an fstat
to the file descriptor associated with stdout
(1), followed by a write
system call with a pointer to the data 2432902008176640000\n
and the length 20
.
Upvotes: 0