BITS 64
GLOBAL _start
SECTION .text align=1
version_text:
db "tinyecho64 (pegasus' utils) version 3", 0x0A
db 'Written by The Almighty Pegasus Epsilon.', 0x0A
db 0x0A
db 'This bad boy is a whopping 1016 bytes.', 0x0A
db 0x0A
db 'Copyright (C) 2005 Pegasus Epsilon', 0x0A
db 'Distribute Unmodified.', 0x0A
version_len: equ $ - version_text
usage:
db 'Usage:'
usage_len: equ $ - usage + 1
help_text:
db ' [OPTION]... [STRING]...', 0x0A
db 'Echo the STRING(s) to standard output.', 0x0A
db 0x0A
db ' -n', 0x09, 0x09, ' do not output the trailing '
db 'newline', 0x0A
; not implemented
;
; db ' -e',0x09,0x09,' enable interpretation of the '
; db 'backslash-escaped characters',0x0A
; db 0x09,0x09,' listed below',0x0A
; db ' -E',0x09,0x09,' disable interpretation of those '
; db 'sequences in STRINGs',0x0A
;
; not implemented
db ' --help', 0x09, ' display this help and exit', 0x0A
db ' --version output version information and '
db 'exit', 0x0A
db 0x0A
; not implemented
;
; db 'Without -E, the following sequences are recognized and '
; db 'interpolated:',0x0A,0x0A
; db ' \NNN the character whose ASCII code is NNN
; db '(octal)',0x0A
; db ' \\ backslash',0x0A
; db ' \a alert (BEL)',0x0A
; db ' \b backspace',0x0A
; db ' \c suppress trailing newline',0x0A
; db ' \f form feed',0x0A
; db ' \n new line',0x0A
; db ' \r carriage return',0x0A
; db ' \t horizontal tab',0x0A
; db ' \v vertical tab',0x0A,0x0A
;
; not implemented
db 'Report bugs to <pegasus@pimpninjas.org>.', 0x0A
help_len: equ $-help_text
space: db ' '
nl: db 0x0A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
global _start
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
_start:
inc rdi ; select stdout
pop rax ; argc
pop rbp ; save our name for --help
pop rsi ; argv[1] (first argument)
test rsi, rsi ; if there are no args, then
jz short finish ; print newline and exit
dec rax ; if rax was not two
dec rax ;
jnz short version ; don't parse long flags
long_flags:
cmp word [rsi], '--' ; if it's not '--'
jnz short version ; skip -- code, otherwise
help:
cmp dword [rsi+2], 'help' ; if it's not '--help'
jnz short version ; skip --help code, otherwise
cmp byte [rsi+6], 0 ; if it's not '--help(null)'
jnz short version ; skip --help code, otherwise
mov rsi, usage
mov dl, usage_len ;
mov al, 1 ; write()
syscall ; go!
mov rdx, rbp ; rdx = argv[0]
.strlen:
cmp byte [rdx], '/' ; if the byte isn't a slash, then
jnz short .noslash ; move along, otherwise
mov rsi, rdx ; move rsi
.noslash:
test byte [rdx], ~0 ; if this byte is null, then
jz short .print ; print it, otherwise
inc rdx ; increment length
jmp short .strlen ; keep looking
.print:
inc rsi ; skip slash
sub rdx, rsi ; rdx = strlen(rsi)
mov al, 1 ; write()
syscall ; go!
mov rsi, help_text ; print help text
mov rdx, help_len ;
xor rax, rax ; write()
mov al, 1 ;
syscall ; go!
jmp short long_flags.exit
help.end:
finish:
mov rsi, nl ; print newline
mov rdx, rbx ; if no newline flag not set
inc rdx ; -1 + 1 == 0, 0 + 1 == 1 :)
xor rax, rax ; write()
mov al, 1 ;
syscall ; go!
exit:
mov al, 60 ; _exit()
dec rdi ; with no error
syscall ; go!
end:
version:
cmp dword [rsi+2], 'vers' ; if it's not '--vers'
jnz short .end ; skip --version code, otherwise
cmp dword [rsi+6], 0x006E6F69
; if it's not '--version(null)'
jnz short .end ; skip --version code, otherwise
.print:
mov rsi, version_text
mov dl, version_len ;
mov al, 1 ; write()
syscall ; go!
long_flags.exit:
jmp short exit
version.end:
long_flags.end:
short_flags:
cmp byte [rsi], '-' ; if the first byte is not a dash
jnz short_flags.end ; it is not a flag
.newline:
cmp word [rsi+1], 0x006E ; if it's not '-n'
jnz short .newline.end ; skip -n code, otherwise
.newline.found:
xor rbx, rbx ; don't print newline
dec rbx ;
pop rsi ; ready next arg
test rsi, rsi ; if it's null
jz short exit ; exit, otherwise
jmp short short_flags ; check the next flag
.newline.end:
short_flags.end:
strlen:
test byte [rsi+rdx], ~0 ; if this byte is null, then
jz short print ; print, otherwise
inc rdx ; increment pointer, and
jmp short strlen ; keep looking
print:
mov al, 1 ; write()
syscall ; go!
xor rdx, rdx ; clear rdx
pop rbp ; ready next arg
test rbp, rbp ; if it's null, then
jz short finish ; finish up and exit
print_space:
mov rsi, space ; print space
inc rdx ; one byte long
xor rax, rax ; write()
mov al, 1 ;
syscall ; go!
dec rdx ; clear rdx
mov rsi, rbp ; ready next arg
jmp short strlen ; do it again