-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsleep.c
More file actions
156 lines (126 loc) · 3.49 KB
/
sleep.c
File metadata and controls
156 lines (126 loc) · 3.49 KB
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#define SYS_write 1
#define SYS_nanosleep 35
#define SYS_exit 60
typedef struct {
long tv_secs;
long tv_nsecs;
} timespec;
long syscall1(long syscall_num, long arg1);
long syscall2(long syscall_num, long arg1, long arg2);
long syscall3(long syscall_num, long arg1, long arg2, long arg3);
void print(char *str);
void sleep(long seconds);
void _exit(int exit_code);
void _start(void);
long syscall1(long syscall_num, long arg1) {
long result;
__asm__ volatile (
"syscall"
: "=a" (result) // 출력: rax 레지스터의 값을 result 변수에 저장
: "a" (syscall_num), "D" (arg1) // 입력: rax에 syscall_num, rdi 에 arg1 저장
: "rcx", "r11", "memory" // syscall이 변경할 수 있는 레지스터 및 메모리
);
return result;
}
long syscall2(long syscall_num, long arg1, long arg2) {
long result;
__asm__ volatile (
"syscall"
: "=a" (result)
: "a" (syscall_num), "D" (arg1), "S" (arg2)
: "rcx", "r11", "memory"
);
return result;
}
long syscall3(long syscall_num, long arg1, long arg2, long arg3) {
long result;
__asm__ volatile (
"syscall"
: "=a" (result)
: "a" (syscall_num), "D" (arg1), "S" (arg2), "d" (arg3)
: "rcx", "r11", "memory"
);
return result;
}
long strlen(char *str) {
char *p = str;
while (p && *p != '\0')
p++;
return p - str;
}
int atoi(char *str) {
int x = 0;
char *p = str;
while (p && *p >= '0' && *p <= '9') {
x *= 10;
x += *p - '0';
p++;
}
return x;
}
char* itoa(int num, char *str) {
int i = 0;
while (num) {
int rem = num % 10;
str[i++] = rem + '0';
num /= 10;
}
str[i] = '\0';
return str;
}
int main(int argc, char *argv[]) {
char buf[32] = {};
print("argc: "); print(itoa(argc, buf)); print("\n");
print("argv[0] "); print(argv[0]); print("\n");
print("argv[1] "); print(argv[1]); print("\n");
if (argc < 2) {
print("Error Input "); print(argv[0]); print("\n");
return 1;
}
int seconds = atoi(argv[1]);
print("Sleeping for "); print(itoa(seconds, buf)); print(" seconds\n");
sleep(seconds);
print("Done\n");
return 0;
}
void print(char *str) {
int fd = 1;
long len = strlen(str);
syscall3(SYS_write, fd, (long)str, len);
}
void sleep(long seconds) {
timespec duration;
duration.tv_secs = seconds;
duration.tv_nsecs = 0;
syscall2(SYS_nanosleep, (long)&duration, 0);
}
void _exit(int exit_code) {
syscall1(SYS_exit, exit_code);
// GCC는 exit 함수가 절대 반환하지 않는다는 것을 알고 있습니다.
// 컴파일러 경고를 없애기 위해 무한 루프를 추가합니다.
for (;;);
}
__attribute__((naked)) void _start() {
__asm__ volatile (
// 1. 프레임 포인터를 0으로 초기화 (ABI 규칙)
"xor rbp, rbp\n"
// 2. main의 첫 번째 인자(argc) 설정
// rsp가 가리키는 메모리 주소의 값(argc)을 rdi 레지스터로 옮깁니다.
// 첫 번째 함수 인자는 rdi 를 통해 전달됩니다.
"mov rdi, [rsp]\n"
// 3. main의 두 번째 인자(argv) 설정
// rsp에서 8바이트 떨어진 주소 (argv의 시작 주소)를 rsi로 옮깁니다.
// 두 번째 함수 인자는 rsi 를 통해 전달됩니다.
"lea rsi, [rsp + 8]\n"
// 4. 스택을 16바이트로 정렬 (ABI 규칙)
// SSE 같은 최신 명령어 세트가 16바이트 정렬된 메모리에 접근할 때
// 성능상 이점을 얻기 위해 필요한 규칙입니다.
"and rsp, -16\n"
// 5. main 함수 호출
"call main\n"
// 6. main의 반환값(rax)를 _exit의 첫 인자(rdi)로 이동
"mov rdi, rax\n"
// 7. _exit 함수 호출
"call _exit\n"
);
}