flat assembler
Message board for the users of flat assembler.

Index > Main > Printing the value of a register to the console

Author
Thread Post new topic Reply to topic
SH4DOW4RE



Joined: 11 Oct 2023
Posts: 2
Location: France
SH4DOW4RE 11 Oct 2023, 08:04
I'm new to Flat Assembler and I've already figured out how to print text to the console:
Code:
format ELF64 executable

segment readable executable
entry main
main:
; print to console
mov rax, 1
mov rdi, 1
mov rsi, hello
mov rdx, hello_len
syscall

; exit with code 0
mov rax, 60
mov rdi, 0
syscall

segment readable writeable
hello db "Hello, World", 10
hello_len = $ - hello
    


But I can't figure out how to print the value of a register. Can someone help me ?
Post 11 Oct 2023, 08:04
View user's profile Send private message Visit poster's website Reply with quote
FlierMate7



Joined: 06 Sep 2023
Posts: 12
FlierMate7 11 Oct 2023, 08:08
You'll need a int_to_hex conversion routine.
Post 11 Oct 2023, 08:08
View user's profile Send private message Reply with quote
SH4DOW4RE



Joined: 11 Oct 2023
Posts: 2
Location: France
SH4DOW4RE 11 Oct 2023, 08:19
FlierMate7 wrote:
You'll need a int_to_hex conversion routine.


How would I do that ?
Post 11 Oct 2023, 08:19
View user's profile Send private message Visit poster's website Reply with quote
FlierMate7



Joined: 06 Sep 2023
Posts: 12
FlierMate7 11 Oct 2023, 10:06
SH4DOW4RE wrote:
FlierMate7 wrote:
You'll need a int_to_hex conversion routine.


How would I do that ?


Hi. You can refer to example code by revolution:

https://board.flatassembler.net/topic.php?t=23007

In "print_hex16" routine.
Post 11 Oct 2023, 10:06
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20363
Location: In your JS exploiting you and your system
revolution 11 Oct 2023, 10:36
To remove the requirement for clicking a new link I repost the short and inefficient code here.
Code:
STDOUT_FILENO           = 1
SYS64_write             = 1

hex_table:      db '0123456789abcdef'

print_hex16:
        ;rax = value
        push    rbx rax rcx rdx
        mov     ecx,16
        lea     rbx,[hex_table]
    .next_nibble:
        rol     rax,4
        mov     edx,eax
        and     edx,0xf
        mov     dl,[rbx + rdx]
        call    print_char
        dec     ecx
        jnz     .next_nibble
        pop     rdx rcx rax rbx
        ret

print_char:
        ;dl = character
        push    rsi rdi rax rcx r11 rdx
        mov     rsi,rsp
        mov     edx,1
        mov     eax,SYS64_write
        mov     edi,STDOUT_FILENO
        syscall
        pop     rdx r11 rcx rax rdi rsi
        ret    
Post 11 Oct 2023, 10:36
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20363
Location: In your JS exploiting you and your system
revolution 11 Oct 2023, 17:22
I created an example that might be slightly more efficient and shows how to suppress or enable leading zeros at assembly time.
Code:
format elf64 executable

STDOUT_FILENO           = 1
SYS64_write             = 1
SYS64_exit_group        = 231

segment readable writeable executable

hex_table:      db '0123456789abcdef'

entry $
        rdtscp
        push    rax rdx rcx

        pop     rax
        call    print_hex16
        mov     dl,10
        call    print_char
        pop     rdx rax
        shl     rdx,32
        or      rax,rdx
        call    print_hex16
        mov     dl,10
        call    print_char
        mov     eax,SYS64_exit_group
        xor     edi,edi
        syscall

print_hex16:
        ;rax = value
        push    rsi rbx rcx rdx
        lea     rbx,[hex_table]
        mov     edx,16
        sub     rsp,rdx
    .next_nibble:
        mov     ecx,eax
        and     ecx,0xf
        mov     cl,[rbx + rcx]
        ; to enable/suppress leading zeros reverse the order of the next two instructions
        shr     rax,4
        dec     edx
        ; to enable/suppress leading zeros reverse the order of the previous two instructions
        mov     [rsp + rdx],cl
        jnz     .next_nibble
        lea     rsi,[rsp + rdx]
        sub     edx,16
        neg     edx
        call    print_string
        add     rsp,16
        pop     rdx rcx rbx rsi
        ret

print_string:
        ;rsi = string
        ;rdx = length
        push    rdi rax rcx r11
        mov     eax,SYS64_write
        mov     edi,STDOUT_FILENO
        syscall
        pop     r11 rcx rax rdi
        ret

print_char:
        ;dl = character
        push    rsi rdi rax rcx r11 rdx
        mov     eax,SYS64_write
        mov     edi,STDOUT_FILENO
        mov     rsi,rsp
        mov     edx,1
        syscall
        pop     rdx r11 rcx rax rdi rsi
        ret    
It produces the digits in the reversed order to the code above, and the exit condition can be either the value reaching zero, or the counter reaching zero, depending upon which instruction last sets the Z flag.
Post 11 Oct 2023, 17:22
View user's profile Send private message Visit poster's website Reply with quote
redsock



Joined: 09 Oct 2009
Posts: 430
Location: Australia
redsock 11 Oct 2023, 20:05
My example is also not terribly efficient but shows a slightly different way to achieve the same thing. Note that my example writes twice to the stack unnecessarily and wastes 7 bytes of stack space after the value and linefeed. Also, if the value to convert to hex is already zero, this unnecessarily writes a 0 instead of skipping the loop entirely Smile
Code:
format elf64 executable

segment readable executable

hexchars: db '0123456789abcdef'

entry $
        mov     rax, 0x3030303030303030 ; all '0'
        mov     ecx, 10                 ; LF
        sub     rsp, 16                 ; stackspace for struct timeval
        mov     rdi, rsp                ; first argument for gettimeofday, struct timeval *
        push    rcx                     ; space for output
        push    rax                     ; space for output
        push    rax                     ; space for output
        mov     eax, 96                 ; gettimeofday syscall
        xor     esi, esi                ; struct timezone *
        syscall
        mov     edx, 15                 ; offset into output to start at, just before the LF
        mov     rax, [rsp+24]           ; struct timeval's tv_sec
        mov     rcx, [rsp+32]           ; struct timeval's tv_usec
        mov     rsi, rsp                ; start of hexchar output and first argument to write syscall
        ; to make our output more interesting, combine tv_sec and tv_usec
        shl     rax, 20                 ; tv_usec only needs 20 bits
        or      rax, rcx                ; add tv_usec to the lower 20 bits
.loop:
        mov     ecx, eax                ; take lower 32 bits of our value
        and     ecx, 0xf                ; only the lowest four bits
        movzx   ebx, byte [rcx+hexchars]; and its hexchar
        mov     [rsi+rdx], bl           ; store at our output
        sub     edx, 1                  ; go backward in our output
        shr     rax, 4                  ; chop four bits we just did
        jnz     .loop
        mov     eax, 1                  ; write syscall
        mov     edi, 1                  ; STDOUT argument to write
        mov     edx, 17                 ; length argument to write
        syscall
        add     rsp, 40                 ; clean up after ourselves
        mov     eax, 60                 ; exit (not group since we are only single threaded)
        xor     edi, edi                ; exit code
        syscall
    

_________________
2 Ton Digital - https://2ton.com.au/
Post 11 Oct 2023, 20:05
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4347
Location: Now
edfed 11 Oct 2023, 20:54
i have an example too.
Code:
print:
;eax = what to print
;return eax print it
.hex:
   call eaxToHexadecimal
   ret
    


or even a simpler code

Code:
c:>hxd.exe
    


Twisted Evil
Post 11 Oct 2023, 20:54
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20363
Location: In your JS exploiting you and your system
revolution 11 Oct 2023, 22:43
edfed wrote:
i have an example too.
Code:
print:
;eax = what to print
;return eax print it
.hex:
   call eaxToHexadecimal
   ret
    
I had some trouble. Can you help?
Code:
flat assembler  version 1.73.31  (16384 kilobytes memory)
edfed.asm [5]:
   call eaxToHexadecimal
processed: call eaxToHexadecimal
error: undefined symbol 'eaxToHexadecimal'.    
edfed wrote:

or even a simpler code

Code:
c:>hxd.exe
    


Twisted Evil
I had some more trouble. Can you help here also?
Code:
~ c:>hxd.exe
bash: c:: command not found
~ ls
hxd.exe    
Post 11 Oct 2023, 22:43
View user's profile Send private message Visit poster's website Reply with quote
Feryno



Joined: 23 Mar 2005
Posts: 509
Location: Czech republic, Slovak republic
Feryno 12 Oct 2023, 10:00
Somebody posted on FASM forum very efficient routine more than 10 years ago, maybe 15 y. I forgot the user name. Or maybe it was another forum.

Code:
align 10h
hexa_64_rax:
; put rax value to ASCII hexadecimal 16 byte buffer at [rdi]
        push    rax
        bswap   rax
        movdqa  xmm3,dqword [Sum1]
        movdqa  xmm4,dqword [Comp1]
        movdqa  xmm2,dqword [Mask1]
        movdqa  xmm5,dqword [Num1]
        movq    xmm0,rax
        movdqa  xmm1,xmm0
        psrlq   xmm0,4
        pand    xmm0,xmm2
        pand    xmm1,xmm2
        punpcklbw       xmm0,xmm1
        movdqa  xmm1,xmm0
        pcmpgtb xmm0,xmm4
        pand    xmm0,xmm5
        paddb   xmm1,xmm3
        paddb   xmm1,xmm0
; we must use movdqu instead of movdqa because we don't know if rdi is aligned 16
        movdqu  dqword [rdi],xmm1
        pop     rax
        ret

align 10h
hexa_64_rax_nobswap:
        movdqa  xmm3,dqword [Sum1]
        movdqa  xmm4,dqword [Comp1]
        movdqa  xmm2,dqword [Mask1]
        movdqa  xmm5,dqword [Num1]
        movq    xmm0,rax
        movdqa  xmm1,xmm0
        psrlq   xmm0,4
        pand    xmm0,xmm2
        pand    xmm1,xmm2
        punpcklbw       xmm0,xmm1
        movdqa  xmm1,xmm0
        pcmpgtb xmm0,xmm4
        pand    xmm0,xmm5
        paddb   xmm1,xmm3
        paddb   xmm1,xmm0
        movdqu  dqword [rdi],xmm1
        ret    


also put this into your data section and align it at 10h - if you do not align you can't use faster movdqa instruction and you have to use slower movdqu:
Code:
align 10h
Sum1                    dq      3030303030303030h, 3030303030303030h
Mask1                   dq      0f0f0f0f0f0f0f0fh, 0f0f0f0f0f0f0f0fh
Comp1                   dq      0909090909090909h, 0909090909090909h
Num1                    dq      0707070707070707h, 0707070707070707h    



edit: very likely it is here:
https://board.flatassembler.net/topic.php?t=11162
Post 12 Oct 2023, 10:00
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20363
Location: In your JS exploiting you and your system
revolution 12 Oct 2023, 13:16
Feryno wrote:
... faster movdqa instruction and you have to use slower movdqu:
Let's test that.
Code:
;       for INST in movdqa movdqu movdqa movdqu ; do fasm dqa-vs-dqu.asm -dLOOPS=999999999 -dOFFSET=0 -dINST=$INST >/dev/null && time ./dqa-vs-dqu ; done

format elf64 executable

SYS64_exit_group        = 231

segment readable writeable executable

align 16
values: db      16 * 32 dup 0

entry $
        mov     rcx,LOOPS
    .loop:
        rept 16 reg:0 {
                INST    xmm#reg,[values + reg * 32 + OFFSET]
        }
        dec     rcx
        jnz     .loop
        mov     eax,SYS64_exit_group
        xor     edi,edi
        syscall    
Code:
~ for INST in movdqa movdqu movdqa movdqu ; do fasm dqa-vs-dqu.asm -dLOOPS=999999999 -dOFFSET=0 -dINST=$INST >/dev/null && time ./dqa-vs-dqu ; done

real    0m2.037s
user    0m2.024s
sys     0m0.000s

real    0m2.031s
user    0m2.016s
sys     0m0.000s

real    0m2.033s
user    0m2.024s
sys     0m0.000s

real    0m2.082s
user    0m2.028s
sys     0m0.000s    
On my system there is no penalty for using dqu vs dqa in that test code. But If I try to use an offset not aligned to 16 then dqa will seg fault, but dqu stills works (just more slowly). So in conclusion I always use dqu. No downside only upsides (for me, on my system; your system and/or code may differ).
Post 12 Oct 2023, 13:16
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.