├── Makefile └── asmsh.asm /Makefile: -------------------------------------------------------------------------------- 1 | all: asmsh 2 | asmsh.o: asmsh.asm 3 | nasm -f macho64 asmsh.asm 4 | asmsh: asmsh.o 5 | ld -lreadline -lc /usr/lib/crt1.o -o asmsh asmsh.o 6 | -------------------------------------------------------------------------------- /asmsh.asm: -------------------------------------------------------------------------------- 1 | default rel 2 | extern _printf 3 | extern _exit 4 | extern _readline 5 | extern _free 6 | extern _strncmp 7 | extern _strcmp 8 | extern _getcwd 9 | extern _getlogin 10 | extern _gethostname 11 | extern _system 12 | extern _fork 13 | extern _execvp 14 | extern _chdir 15 | extern _snprintf 16 | extern _strtok 17 | extern _memset 18 | extern _waitpid 19 | extern _perror 20 | extern _using_history 21 | extern _add_history 22 | extern _read_history 23 | extern _write_history 24 | 25 | section .data 26 | UNIX_PROMPT: db "%s@%s:%s$ ",0 27 | ZERO_STR: db 10,0 28 | STRTOK_SEP_STR: db " ",0 29 | ERR_EXEC_STR: db "Error executing command",0 30 | 31 | QUIT_CMD_STR: db "quit",0 32 | EXIT_CMD_STR: db "exit",0 33 | HISTORY_CMD_STR: db "history",0 34 | CD_CMD_STR: db "cd ",0 35 | 36 | 37 | PROMPT_STR: times 4096 db 0 38 | HOSTNAME_STR: times 50 db 0 39 | EXEC_CMD: times 2 dd 0 40 | 41 | ARGS: times 64 dd 0 42 | 43 | section .text 44 | global _main 45 | 46 | _main: 47 | push rbp 48 | call _using_history 49 | pop rbp 50 | 51 | mov rdi,0 52 | push rbp 53 | call _read_history 54 | pop rbp 55 | 56 | sh_loop: 57 | call unix_prompt 58 | mov r14,1 59 | mov r15,1 60 | mov rax,1 61 | 62 | push rbp 63 | mov rdi,PROMPT_STR 64 | call _readline 65 | pop rbp 66 | 67 | mov r14,rax 68 | 69 | mov rdi,r14 70 | push rbp 71 | call _add_history 72 | pop rbp 73 | 74 | mov rdi,r14 75 | mov rsi,ZERO_STR 76 | mov rdx,1 77 | push rbp 78 | call _strncmp 79 | pop rbp 80 | cmp rax,0 81 | je sh_loop 82 | 83 | mov rdi,r14 84 | mov rsi,QUIT_CMD_STR 85 | push rbp 86 | call _strcmp 87 | pop rbp 88 | 89 | mov r15,rax 90 | cmp r15,0 91 | je quit 92 | 93 | mov rdi,r14 94 | mov rsi,EXIT_CMD_STR 95 | push rbp 96 | call _strcmp 97 | pop rbp 98 | 99 | mov r15,rax 100 | cmp r15,0 101 | je quit 102 | 103 | mov rdi,r14 104 | mov rsi,CD_CMD_STR 105 | mov rdx,3 106 | push rbp 107 | call _strncmp 108 | pop rbp 109 | 110 | mov r13,rax 111 | cmp r13,0 112 | je handle_cd 113 | 114 | mov rdi,r14 115 | call split_line 116 | aftersplit: 117 | push rbp 118 | call _fork 119 | pop rbp 120 | cmp rax,0 121 | je spawn_cmd 122 | mov rdi,rax ; we're the parent, setup waitpid 123 | mov rsi,0 124 | mov rdx,0 125 | push rbp 126 | call _waitpid 127 | pop rbp 128 | mov r15,1 129 | jmp freecmdline 130 | 131 | spawn_cmd: 132 | push rbp 133 | mov rdi,[EXEC_CMD] 134 | mov rsi,ARGS 135 | mov rdx,0 136 | call _execvp 137 | ; if we get to here, something went wrong with the _execvp call 138 | mov rdi,ERR_EXEC_STR 139 | call _perror 140 | jmp quit ; we are still in the fork() child, so die 141 | 142 | freecmdline: 143 | push rbp 144 | mov rdi,r14 145 | call _free 146 | pop rbp 147 | 148 | cmp r15,0 149 | jne sh_loop 150 | je quit 151 | 152 | quit: 153 | mov rdi,0 154 | push rbp 155 | call _write_history 156 | pop rbp 157 | 158 | push rbp 159 | mov rdi,0 160 | mov rax,0 161 | call _exit 162 | pop rbp 163 | 164 | 165 | handle_cd: 166 | mov r12,3 167 | add r12,r14 168 | mov rdi,r12 169 | mov rsi, STRTOK_SEP_STR 170 | push rbp 171 | call _strtok ; cheap way to right trim whitespace 172 | pop rbp 173 | push rbp 174 | mov rdi, rax 175 | call _chdir 176 | pop rbp 177 | jmp freecmdline 178 | 179 | split_line: 180 | ;rdi register set by caller 181 | mov r13, rdi ; save rdi 182 | 183 | mov rdi,ARGS ; clear ARGS 184 | mov rsi,0 185 | mov rdx,128 ; 64 64-bit pointers comes to 128 bytes 186 | call _memset 187 | 188 | mov rdi, r13 189 | mov rsi, STRTOK_SEP_STR 190 | call _strtok 191 | mov [EXEC_CMD],rax 192 | 193 | ; store argv[0] 194 | mov r13,ARGS 195 | add r13,0 196 | mov [r13], rax 197 | 198 | split_line_loop: 199 | mov rdi, 0 ; invoke strtok() again to get command params 200 | mov rsi, STRTOK_SEP_STR 201 | call _strtok 202 | cmp rax, 0 203 | 204 | je split_line_done ; if strtok returns NULL, we're done 205 | 206 | mov r13,ARGS ; increment the index into ARGS and store the param 207 | add r13,8 208 | mov [r13], rax 209 | 210 | jne split_line_loop 211 | 212 | split_line_done: 213 | mov rax,0 214 | totally: 215 | ret 216 | 217 | unix_prompt: 218 | mov rdi,0 219 | call _getlogin 220 | mov r12, rax 221 | 222 | mov rdi, HOSTNAME_STR 223 | mov rsi, 49 224 | call _gethostname 225 | mov r13, HOSTNAME_STR 226 | 227 | mov rdi,0 228 | call _getcwd 229 | mov r14,rax 230 | 231 | mov rdi,PROMPT_STR 232 | mov rsi,4096 233 | mov rdx,UNIX_PROMPT 234 | mov rcx,r12 235 | mov r8,r13 236 | mov r9,r14 237 | call _snprintf 238 | mov rdi,r14 239 | call _free 240 | 241 | ret 242 | --------------------------------------------------------------------------------