-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathnap.asm
138 lines (112 loc) · 4.65 KB
/
nap.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
; Usage: nap [seconds]
;
; Command-line argument is optional. Defaults to 10 seconds.
;
; To build for x86-64 Linux:
; nasm -f elf64 nap.asm && ld -m elf_x86_64 -o nap nap.o
;
; To build with debug info:
; nasm -f elf64 -F dwarf -g nap.asm && ld -m elf_x86_64 -o nap nap.o
; First we allocate memory to store our variables and constants
section .data
exit_code DD 0
timeval:
tv_sec DD 10 ; Number of seconds to sleep. Default to 10.
tv_usec DD 0 ; Number of nanoseconds to sleep (this is added to seconds, above)
; All strings end with newline char (0xA) and null byte (0x0)
start_msg DB 'Sleeping...',0xA,0
start_msg_len EQU $ - start_msg
end_msg DB 'Done!',0xA,0
end_msg_len EQU $ - end_msg
bad_input_msg DB 'Bad input. Sleeping for default of 10 seconds',0xA,0
bad_input_msg_len EQU $ - bad_input_msg
input_overflow_msg DB 'Input too large. Sleeping for default of 10 seconds',0xA,0
input_overflow_msg_len EQU $ - input_overflow_msg
; Executable code
section .text
global _start
_start:
; Check for command-line argument and use it if we have one.
;
; When this program begins, the rsp stack-pointer register will hold the address of the argument count (argc in C).
; The addresses of the arguments (argv in C) are located at 16-byte offsets from rsp:
; argc = [rsp]
; argv = [rsp + 16 * ARG_NUMBER]
mov r8, [rsp] ; Store value of argc into register r8. This is the number of arguments, including the program name.
cmp r8, 2 ; Check that we received exactly one command-line argument
jnz .do_sleep ; If not, we'll just use the default value: 10 seconds
; Convert first command-line argument from string to integer (in C, this is the atoi function).
xor eax, eax ; Initialize a register to zero to store our result
mov r9, [rsp+16] ; Store address of first command-line argument in register r9
mov ebx, 10 ; Load a register since immediate-mode multiply doesn't write the high word to EDX
; This label marks the top of the loop
.begin:
; Copy next byte from argv[1] string into ecx register
movzx ecx, byte[r9]
; A null-byte signifies the end of the string. We're done processing, so jump to end of loop
cmp ecx, 0
je .end
; Here we check for bad characters in the input. If we detect any bad characters, we just use the default sleep time.
cmp ecx, '0' ; If user entered a char below the ASCII integers, it's bad input.
jb .bad_input ; Jump-if-Below does an unsigned comparison
cmp ecx, '9' ; If user entered a char above the ASCII integers, it's bad input.
ja .bad_input ; Jump-if-Above does an unsigned comparison
; "Convert" character to its integer by subtracting ASCII '0'
sub ecx, '0'
; Multiply the sum in EAX by 10 for the decimal place.
; (On the first time through the loop, EAX is 0, so this is still 0.)
imul ebx ; Multiply by 10
cmp edx, 0 ; Check for multiplication overflow
jne .overflow
; Add the new integer to EAX
add eax, ecx
; If the sign bit was set, the input was too large and EAX overflowed
js .overflow
; If the carry bit was set, the input was too large and EAX overflowed
jc .overflow
; Increment pointer to next byte in the argv[1] string
inc r9
; Jump to top of loop to process the next character
jmp .begin
.end:
mov dword [tv_sec], eax ; Store the result
.do_sleep:
; Print start message
mov eax, 4 ; sys_write
mov ebx, 1 ; write to the stdout stream
mov ecx, start_msg
mov edx, start_msg_len
int 0x80
; Sleep for argv[1] seconds and 0 nanoseconds
mov eax, 162 ; sys_nanosleep
mov ebx, timeval
mov ecx, 0
int 0x80
; Print done message
mov eax, 4 ; sys_write
mov ebx, 1
mov ecx, end_msg
mov edx, end_msg_len
int 0x80
; exit
mov eax, 1 ; sys_exit
mov ebx, [exit_code] ; set exit status code
int 0x80
; Set exit status code to 1 and print "bad input" message
.bad_input:
mov dword [exit_code], 1
mov eax, 4 ; sys_write
mov ebx, 2 ; write to std_error
mov ecx, bad_input_msg
mov edx, bad_input_msg_len
int 0x80
jmp .do_sleep
; Set exit status code to 2 and print "input too large" message
.overflow:
mov dword [exit_code], 2
mov eax, 4 ; sys_write
mov ebx, 2 ; write to std_error
mov ecx, input_overflow_msg
mov edx, input_overflow_msg_len
int 0x80
jmp .do_sleep