NASM Forum > Example Code
My own 64-bit `puts' instruction (No length required)
fredericopissarra:
--- Quote from: MediocreVeg1 on January 18, 2021, 03:06:55 PM ---
--- Quote ---I found strange your approach, since sub rdi,rbx (with rbx == 0) do nothing, except affect the flags. Din't you mean to use 'mov rbx,rdi' instead of 'xor rbx,rbx'?
--- End quote ---
Maybe I'm not understanding how scas works, but isn't the result of scasb stored in rbx in 64-bit assembly? That's why I cleared it with XOR before using scasb and why I substracted it from rdi (which has starting address of string). I'm probably wrong here though.
--- End quote ---
Nope... repnz scasb searches for AL in RDI and forward (increasing RDI and decreasing RCX). It won't change RBX.
--- Quote ---
--- Quote ---PS: Try to use E?? registers as many times as possible. Using R?? will imply a REX prefix and bigger instructions. moving and doing arithmetic/logical operations to E?? registers will automatically zero the upper 32 bits of R?? registers for you (this doen't work in a few instructions as, for example, CDQ [will zero upper RDX but not upper RAX).
--- End quote ---
Wouldn't the assembler get confused if I used 64-bit syscalls on 32-bit registers? Or if I put some arguments of a syscall in R?? registers and others in E?? registers?
--- End quote ---
It won't get confused because E?? registers are part of R?? registers. When you use a R?? register NASM is forced to add a prefix to the instruction (REX prefix). This prefix isn't added if you use E?? registers. Of course, if the argument is an address (a pointer) you are forced to use R??.
--- Quote ---
--- Quote ---S: Notice in my routine, if '\0' isn't found in a block of 2³²-1 bytes it returns -1 (all bits set) in RAX. This allows you to test an error:
--- End quote ---
Yeah, I put it into my procedure as well after you showed your example. Wouldn't this event be highly unlikely though? I think 2^32-1 is like 4294967295 bytes so every single byte after the starting address of the string would have to be non-zero, right?
--- End quote ---
Yep... The problem when you ser RCX to -1 is that, theoretically you can search a 18446744073709551615 bytes long string. If such string exists (not possible), than REP SCASB would take 192 YEARS to complete (@ 3 GHz). If you restrict the string to 2³²-1 bytes, if such string exists (improbable), it would take only 1.5 seconds to scan.
MediocreVeg1:
--- Quote ---Nope... repnz scasb searches for AL in RDI and forward (increasing RDI and decreasing RCX). It won't change RBX.
--- End quote ---
Oh man, I'm so stupid. How does my procedure even work then? Sheesh, now I'm even confused as to how my own procedure works :P
--- Quote ---It won't get confused because E?? registers are part of R?? registers. When you use a R?? register NASM is forced to add a prefix to the instruction (REX prefix). This prefix isn't added if you use E?? registers. Of course, if the argument is an address (a pointer) you are forced to use R??
--- End quote ---
Oh, I see. Would that mean that I would be able to enter the call number in eax too? And for example in the second argument of a system call, would I use ebx or edi for 32-bit registers?
--- Quote ---Yep... The problem when you ser RCX to -1 is that, theoretically you can search a 18446744073709551615 bytes long string. If such string exists (not possible), than REP SCASB would take 192 YEARS to complete (@ 3 GHz). If you restrict the string to 2³²-1 bytes, if such string exists (improbable), it would take only 1.5 seconds to scan.
--- End quote ---
Wow, that's... a lot. Anyway, I think this answers my question. Thanks.
fredericopissarra:
--- Quote from: MediocreVeg1 ---Oh man, I'm so stupid. How does my procedure even work then? Sheesh, now I'm even confused as to how my own procedure works :P
--- End quote ---
I confesss I cannot see how it works, too... ;)
--- Quote ---Oh, I see. Would that mean that I would be able to enter the call number in eax too? And for example in the second argument of a system call, would I use ebx or edi for 32-bit registers?
--- End quote ---
A simple example. If you want to print a string you can do:
--- Code: --- bits 64
default rel ; Use RIP relative addressing.
section .rodata
msg: db `Hello\n`
msg_len equ $ - msg
section .text
global writemsg
writemsg:
mov eax,1 ; EAX, instead of RAX will zero upper 32 bits.
mov edi,eax ; RDI=STDOUT_FILENO (upper 32 bits zeroed).
lea rsi,[msg] ; Need to load RSI (because it is a pointer). LEA because 'msg' is RIP relative.
mov edx,msg_len ; RDX (upper 32 bits zeroed).
syscall
ret
--- End code ---
Those E?? movs are shorter than if you use R?? regs.
[]s
Fred
MediocreVeg1:
--- Quote ---I confesss I cannot see how it works, too... ;)
--- End quote ---
Yeah, I think I'll change my thing to your not solution so I at least understand what is going on.
And about the registers, I think I finally get it now. Thanks for all the help!
munair:
Just getting my feed wet with 64 bits (yes, my very first code) :D. If I understand correctly, there is some optimization to be gained from using 32 bit registers with the string length (which would probably never exceed 4GB).
As usual, no C externals here. ;D
--- Code: ---; nasm -f elf64 puts.asm
; ld -m elf_x86_64 puts.o -o puts
bits 64
section .text
global _start
_start:
mov rdi, msg ; string
call strlen ; length
test rax, rax ; anyhing?
jz .__out
call puts ; show it
.__out:
mov rax, 0x3c
xor rdi, rdi
syscall
puts:
mov rsi, rdi ; string
mov rdi, 1 ; stdout
mov rdx, rax ; length (from strlen)
mov rax, 1 ; write
syscall
ret
strlen:
push rdi ; save address
sub rcx, rcx
not rcx ; rcx -1
xor eax, eax
cld ; count forward
repne scasb
not rcx
lea rax, [rcx - 1] ; length
pop rdi
ret
section .data
msg db "Hello world!", 10, 0
--- End code ---
Navigation
[0] Message Index
[#] Next page
[*] Previous page
Go to full version