BITS 64
org 0x400000
ehdr: ; ELF header
db 0x7F, "ELF", 2, 1, 1, 0 ;1, 1, 1?
times 8 db 0
dw 2 ;?
dw 0x3E ;?
dd 1
dq _start
dq phdr - $$
dq 0 ; section headers start, we don't have one
dd 0
dw ehdrsize
dw phdrsize
dw 1
dw 0
dw 0
dw 0
ehdrsize equ $ - ehdr
phdr: ; mo header nasty
dd 1
dd 0
dd $$
dd $$
dd end - $$
dd end - $$
dd 5
dd 0x1000
phdrsize equ $ - phdr
space: db ' '
nl: db 0x0A
version_text:
db "echo (pegasus' utils) version 3", 0x0A
db 'Written by The Almighty Pegasus Epsilon.', 0x0A
db 0x0A
db 'This bad boy is a whopping 731 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
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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
global _start
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
_start:
inc rbx ; select stdout
pop rax ; argc
pop rdi ; save our name for --help
pop rcx ; argv[1] (first argument)
test rcx, rcx ; if there are no args, then
jz short finish_bounce ; print newline and exit
dec rax ; if rax was not two
dec rax ;
jnz short long_flags.end ; don't parse long flags
long_flags:
cmp word [rcx], '--' ; if it's not '--'
jne short long_flags.end ; skip -- code, otherwise
help:
cmp dword [rcx+2], 'help' ; if it's not '--help'
jne short .end ; skip --help code, otherwise
cmp byte [rcx+6], 0 ; if it's not '--help(null)'
jne short .end ; skip --help code, otherwise
mov rcx, usage ; print "Usage: "
mov dl, usage_len ;
mov al, 4 ; write()
int 0x80 ; go!
mov rcx, rdi ; print our name
xor rdx, rdx ; clear rdx
.strlen:
test byte [rcx+rdx], ~0 ; if this byte is null, then
jz short .print ; print it, otherwise
inc rdx ; increment counter, and
jmp short .strlen ; keep looking
.print:
mov al, 4 ; write()
int 0x80 ; go!
mov rcx, help_text ; print help text
mov rdx, help_len ;
xor rax, rax ; write()
mov al, 4 ;
int 0x80 ; go!
jmp short long_flags.exit
help.end:
version:
cmp dword [rcx+2], 'vers' ; if it's not '--vers'
jne short .end ; skip --version code, otherwise
cmp dword [rcx+6], 0x006E6F69
; if it's not '--version(null)'
jne short .end ; skip --version code, otherwise
.print:
mov rcx, version_text ; print version text
mov dl, version_len ;
mov al, 4 ; write()
int 0x80 ; go!
long_flags.exit:
jmp short exit
version.end:
finish_bounce:
jmp short finish
long_flags.end:
short_flags:
cmp byte [rcx], '-' ; if the first byte is not a dash
jne short_flags.end ; it is not a flag
.n:
cmp word [rcx+1], 0x006E ; if it's not '-n'
jne short .n.end ; skip -n code, otherwise
.n.found:
xor rsi, rsi ; don't print newline
dec rsi ;
pop rcx ; ready next arg
test rcx, rcx ; if it's null
jz short exit ; exit, otherwise
jmp short short_flags ; check the next flag
.n.end:
short_flags.end:
strlen:
test byte [rcx+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, 4 ; write()
int 0x80 ; go!
xor rdx, rdx ; clear rdx
pop rdi ; check next arg
test rdi, rdi ; if it's null, then
jz short finish ; finish up and exit
print_space:
mov rcx, space ; print space
inc rdx ; one byte long
xor rax, rax ; write()
mov al, 4 ;
int 0x80 ; go!
dec rdx ; clear rdx
mov rcx, rdi ; ready next arg
jmp short strlen ; do it again
finish:
mov rcx, nl ; print newline
mov rdx, rsi ; check rbp
inc rdx ; -1 + 1 == 0, 0 + 1 == 1 :)
xor rax, rax ; write()
mov al, 4 ;
int 0x80 ; go!
exit:
mov al, 1 ; _exit()
dec rbx ; with no error
int 0x80 ; go!
end: