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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
|
; **************************************************************************** ;
; ;
; ::: :::::::: ;
; ft_atoi_base.s :+: :+: :+: ;
; +:+ +:+ +:+ ;
; By: cacharle <marvin@42.fr> +;+ +:+ +;+ ;
; +;+;+;+;+;+ +;+ ;
; Created: 2019/11/22 03:59:15 by cacharle ;+; ;+; ;
; Updated: 2019/11/22 21:18:08 by cacharle ;;; ;;;;;;;;.fr ;
; ;
; **************************************************************************** ;
; Only need to save reg if we use them after
; caller rules:
; 1. save caller-saved reg r10, r11
; /!\ all param reg
; 2. pass param with regs rdi, rsi, rdx, rcx, r8, r9
; if there is more pass them onto the stack in reverse order
; 3. use call
; 4. restore stack state by removing passed on the stack param
; 5. return value of callee in rax
; 6. restore the caller-saved register and saved passed params
; We can assume that no other register has been altered.
; callee rules:
; 1. allocate local variables by sub sum of sizes of thoses var to rsp
; the stack grows downward so we will access those local by adding to rsp.
; 2. push callee-saved reg onto the stack: rbx, rbp, r12, r13, r14, r15.
;
; >>> function body <<<
;
; 3. place return value in rax
; 4. restore callee-saved registers
; 5. remove local var, add to the stack the previoulsy subtracted amount.
; 6. use ret
%ifdef __LINUX__
%define M_FT_STRLEN ft_strlen
%define M_FT_ATOI_BASE ft_atoi_base
%else
%define M_FT_STRLEN _ft_strlen
%define M_FT_ATOI_BASE _ft_atoi_base
%endif
extern M_FT_STRLEN
global M_FT_ATOI_BASE
section .text
; int ft_atoi_base(const char *str, const char *base);
M_FT_ATOI_BASE:
; ===prolog===
; long int nb (8)
; int radix (4)
; int is_negative (4)
sub rsp, 16
mov qword [rsp], 0x0 ; nb = 0
mov dword [rsp + 8], 0x0 ; radix = 0
mov dword [rsp + 12], 0x0 ; is_negative = 0
push rbx
push r11
push r15
; ===body===
; check if the base is valid
push rdi
mov rdi, rsi
call _check_base
pop rdi
cmp eax, 0x0
je FT_ATOI_BASE_ERROR
; ignore space in front
mov rbx, -1 ; rbx is rdi str index
FT_ATOI_BASE_IGNORE_SPACES:
inc rbx
push rdi
mov dil, byte [rdi + rbx]
call _ft_isspace
pop rdi
cmp rax, 1
je FT_ATOI_BASE_IGNORE_SPACES
; ignore '+', '-' reverse the current sign
mov qword [rsp], 0x0 ; nb = 0
mov dword [rsp + 8], 0x0 ; radix = 0
mov dword [rsp + 12], 0x0 ; is_negative = 0
mov dword [rsp + 12], 0x0 ; weird behavior FIXME
dec rbx
jmp FT_ATOI_BASE_SIGN_LOOP
FT_ATOI_BASE_SIGN_LOOP_FOUND_NEG:
not dword [rsp + 12]
FT_ATOI_BASE_SIGN_LOOP:
inc rbx
cmp byte [rdi + rbx], 0x2b ; if '+'
je FT_ATOI_BASE_SIGN_LOOP
cmp byte [rdi + rbx], 0x2d ; if '-'
je FT_ATOI_BASE_SIGN_LOOP_FOUND_NEG
; base radix
push rdi
mov rdi, rsi
call M_FT_STRLEN
pop rdi
mov dword [rsp + 8], eax
; main loop
FT_ATOI_BASE_LOOP:
push rdi
push rsi
mov dil, byte [rdi + rbx]
call _base_pos ; get value of the current char int the base
pop rsi
pop rdi
cmp rax, -1 ; if is not in base break
je FT_ATOI_BASE_LOOP_END
mov r11, [rsp] ; place nb in register for multiplication
xor r15, r15 ; same for radix
mov r15d, dword [rsp + 8]
imul r11, r15 ; multiply by the radix
mov [rsp], r11 ; store multiplication result
add [rsp], rax ; add the current value
inc rbx
jmp FT_ATOI_BASE_LOOP
FT_ATOI_BASE_LOOP_END:
cmp dword [rsp + 12], 0
je FT_ATOI_BASE_END
neg qword [rsp]
; ===epilog===
FT_ATOI_BASE_END:
mov rax, [rsp]
pop r15
pop r11
pop rbx
add rsp, 16
ret
FT_ATOI_BASE_ERROR:
mov rax, 0x0
pop r15
pop r11
pop rbx
add rsp, 16
ret
; dil: char searched
; rsi: char *base
_base_pos:
mov rax, -1
BASE_POS_LOOP:
inc rax
cmp byte [rsi + rax], 0 ; if '\0' char not in base
je BASE_POS_NOT_FOUND
cmp dil, byte [rsi + rax] ; loop until '\0' or found
jne BASE_POS_LOOP
ret
BASE_POS_NOT_FOUND:
mov rax, -1
ret
; rdi: char *base
_check_base:
sub rsp, 4
mov dword [rsp], 0
; check for empty or size 1 base
push rdi
call M_FT_STRLEN
pop rdi
cmp rax, 2
jl CHECK_BASE_FALSE
; xor rcx, rcx
CHECK_BASE_LOOP:
cmp byte [rdi], 0
je CHECK_BASE_LOOP_END
cmp byte [rdi], 0x2b ; check '+'
je CHECK_BASE_FALSE
cmp byte [rdi], 0x2d ; check '-'
je CHECK_BASE_FALSE
; check for spaces
push rdi
mov dil, [rdi] ; pass current char as argument
call _ft_isspace
pop rdi
cmp rax, 1
je CHECK_BASE_FALSE
; check for duplicates in base
xor rcx, rcx ; index from curr +1
CHECK_BASE_DUP_LOOP:
inc rcx
mov r10b, byte [rdi] ; r10b = checked char
cmp r10b, byte [rdi + rcx] ; check if found dup
je CHECK_BASE_FALSE
cmp byte [rdi + rcx], 0 ; if \0 end dup check
jne CHECK_BASE_DUP_LOOP
inc rdi
jmp CHECK_BASE_LOOP
CHECK_BASE_LOOP_END:
add rsp, 4
mov rax, 1
ret
CHECK_BASE_FALSE:
add rsp, 4
xor rax, rax
ret
; dil: char c
_ft_isspace:
cmp dil, 0x20
je ISSPACE_TRUE
sub dil, 0x9
cmp dil, 0x5
jl ISSPACE_TRUE
xor rax, rax
ret
ISSPACE_TRUE:
mov rax, 0x1
ret
|