assemblifying a bash script
first and foremost, to my chinese brothers and sisters out there,
way back, i frequently found myself descending deep into the recesses of my git repository. i keep all sorts of stuff there. but more importantly, i keep all my work neatly categorized in special folders inside. anyway, i decided to come up with some remedy, enter bash scripting. i made a (pretty much) straight forward script to create a symlink in my home directory called “workdir” so if ever i wanted to go back to my work, i’d only cd ~/workdir right away.
#!/bin/bash
# this script makes a symlink "~/workdir" to
# the pwd or to the first argument
CWD=`pwd`
SHORTCUT=/home/amerei/workdir
# create a symlink
# if a symlink exists remove it first
function my_linkie {
if [ -h $SHORTCUT ]; then
rm $SHORTCUT
fi
ln -s $CWD $SHORTCUT
exit 0
}
# if there are no arguments assume
# current directory to be the target
# otherwise, honor only the first argument
if [ $# = 0 ] ; then
my_linkie
else
# i don't want a broken symlink
# file exists and is a directory
if [ -d $1 ]; then
CWD=$1
my_linkie
fi
echo "$1 is invalid"
exit 1
fi
one day, i was bored so i tried to implement the script above in assembly. here goes..
; /usr/include/asm/unistd.h %define sys_stat 0x6a %define sys_symlink 0x53 %define sys_readlink 0x55 %define sys_unlink 0x0a ; /usr/include/asm/errno.h %define EEXIST -0x11 ; st_mode field (man 2 stat) %define S_IFDIR 0040000q ; custom definitions %define bufsiz 0x20000 ; enough length? ; /usr/include/asm/stat.h struc _stat .st_dev resw 1 .__pad1 resw 1 .st_ino resd 1 .st_mode resw 1 .st_nlink resw 1 .st_uid resw 1 .st_gid resw 1 .st_rdev resw 1 .__pad2 resd 1 .st_size resd 1 .st_blksize resd 1 .st_blocks resd 1 .st_atime resd 1 .__unused1 resd 1 .st_mtime resd 1 .__unused2 resd 1 .st_ctime resd 1 .__unused3 resd 1 .__unused4 resd 1 .__unused5 resd 1 endstruc shortcut: db '/home/amerei/workdir',0x0 proc_cwd: db '/proc/self/cwd', 0x0 global _start section .text _start: pop ebx ; argc dec ebx pop ebx ; argv[0] jnz .getargv ; has arguments .getcwd mov edx, bufsiz ; bufsiz mov ecx, pwd ; char *buf mov ebx, proc_cwd ; const char *path mov eax, sys_readlink ; sys_readlink() int 80h test eax, eax ; toggle sign flag js error ; exit(errno) mov edi, pwd ; see .mylinkie jmp .mylinkie .getargv: pop edi ; first argument mov ecx, stat_buf ; struct stat *buf mov ebx, edi ; const char *filename mov eax, sys_stat ; sys_stat() int 0x80 test eax, eax ; toggle sign flag js error ; exit(errno) mov eax, [stat_buf+_stat.st_mode] mov ebx, S_IFDIR test eax, ebx jz error ; file is not a folder .mylinkie: mov ecx, shortcut ; const char *newpath mov ebx, edi ; const char *oldpath mov eax, sys_symlink ; sys_symlink() int 0x80 test eax, eax ; toggle sign flag jns .bye cmp eax, EEXIST ; check for EEXIST jne error mov ebx, shortcut mov eax, sys_unlink int 80h test eax, eax ; bugger! js error ; deal with it. jmp .mylinkie ; another shot .bye: xor eax, eax inc eax xor ebx, ebx int 80h error: mov ebx, eax neg ebx ; -(eax) = errno mov eax, 1 int 80h section .bss stat_buf resb _stat_size pwd resb bufsizi had a hard time on how to implement strucs in nasm. again, thanks to frank kotler i kinda got the hang of those. he confirmed that i needed to create an instance of a struc as opposed to just prototyping one inside the .bss segment the only thing i hate about that implementation above is that i have to declare an entire stat structure but use only one of it’s elements. it’s current standing size is 596 bytes! and if i compare that to the bash script version’s size of 598 bytes, i think i did a rather pathetic job. there are just some things that are better off scripted. oh well, at least i learned how to use sys_stat to get some basic file information. currently, i’m psyching myself out to tackle streaming SIMD extensions in pentium III (sse). i hope i won’t lose my mind trying to understand that!
oh! and yeah… to steph,
praying for better times.
wishing you a belated happy birthday.
from your biggest fan,
-me
