OLD | NEW |
| (Empty) |
1 # Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 # This validator test was taken from branch "x86-64" in the repo: | |
6 # https://github.com/mseaborn/x86-decoder | |
7 # The test was modified to address intentional validator differences. | |
8 | |
9 import subprocess | |
10 | |
11 | |
12 def WriteFile(filename, data): | |
13 fh = open(filename, "w") | |
14 try: | |
15 fh.write(data) | |
16 finally: | |
17 fh.close() | |
18 | |
19 | |
20 bits = 64 | |
21 | |
22 test_cases = [] | |
23 | |
24 def TestCase(asm, accept): | |
25 def Func(): | |
26 print '* test %r' % asm | |
27 full_asm = asm + '\n.p2align 5, 0x90\n' | |
28 WriteFile('tmp.S', full_asm) | |
29 subprocess.check_call(['gcc', '-m%i' % bits, '-c', 'tmp.S', '-o', 'tmp.o']) | |
30 rc = subprocess.call(['./dfa_ncval', 'tmp.o']) | |
31 if accept: | |
32 assert rc == 0, rc | |
33 else: | |
34 assert rc == 1, rc | |
35 test_cases.append(Func) | |
36 | |
37 | |
38 # Check some simple allowed instructions. | |
39 TestCase(accept=True, asm=""" | |
40 nop | |
41 hlt | |
42 mov $0x12345678, %rax | |
43 mov $0x1234567812345678, %rax | |
44 """) | |
45 | |
46 # Check a disallowed instruction. | |
47 TestCase(accept=False, asm=""" | |
48 nop | |
49 int $0x80 | |
50 """) | |
51 | |
52 TestCase(accept=False, asm='ret') | |
53 | |
54 TestCase(accept=False, asm='syscall') | |
55 | |
56 # Instruction bundle overflow. | |
57 TestCase(accept=False, asm=""" | |
58 mov $0x1234567812345678, %rax | |
59 mov $0x1234567812345678, %rax | |
60 mov $0x1234567812345678, %rax | |
61 mov $0x1234567812345678, %rax | |
62 """) | |
63 | |
64 # Forwards and backwards jumps. | |
65 TestCase(accept=True, asm=""" | |
66 nop | |
67 jmp label2 | |
68 label1: | |
69 jmp label1 | |
70 jmp label1 | |
71 label2: | |
72 jmp label1 | |
73 """) | |
74 | |
75 # Out-of-range unaligned jump. | |
76 TestCase(accept=False, asm=""" | |
77 label: | |
78 jmp label - 1 | |
79 """) | |
80 | |
81 # Out-of-range unaligned jump. | |
82 TestCase(accept=False, asm=""" | |
83 jmp label + 1 | |
84 .p2align 5 | |
85 label: | |
86 """) | |
87 | |
88 # Jump into instruction. | |
89 TestCase(accept=False, asm=""" | |
90 label: | |
91 mov $0x1234567812345678, %rax | |
92 jmp label + 1 | |
93 """) | |
94 | |
95 | |
96 # Unmasked indirect jumps are disallowed. | |
97 TestCase(accept=False, asm='jmp *%rax') | |
98 TestCase(accept=False, asm='jmp *(%rax)') | |
99 TestCase(accept=False, asm='call *%rax') | |
100 TestCase(accept=False, asm='call *(%rax)') | |
101 | |
102 # Masking instructions on their own are allowed. | |
103 TestCase(accept=True, asm='and $~31, %eax') | |
104 TestCase(accept=True, asm='and $~31, %ebx') | |
105 TestCase(accept=True, asm='and $~31, %rax') | |
106 TestCase(accept=True, asm='and $~31, %rbx') | |
107 TestCase(accept=True, asm='and $~31, %eax; add %r15, %rax') | |
108 TestCase(accept=True, asm='and $~31, %ebx; add %r15, %rbx') | |
109 | |
110 # Masked indirect jumps are allowed. | |
111 TestCase(accept=True, asm='and $~31, %eax; add %r15, %rax; jmp *%rax') | |
112 TestCase(accept=True, asm='and $~31, %ebx; add %r15, %rbx; call *%rbx') | |
113 | |
114 # The registers must match up for the mask and the jump. | |
115 TestCase(accept=False, asm='and $~31, %ebx; add %r15, %rax; jmp *%rax') | |
116 TestCase(accept=False, asm='and $~31, %eax; add %r15, %rbx; jmp *%rax') | |
117 TestCase(accept=False, asm='and $~31, %eax; add %r15, %rax; jmp *%rbx') | |
118 TestCase(accept=False, asm='and $~31, %eax; add %r15, %rbx; jmp *%rbx') | |
119 TestCase(accept=False, asm='and $~31, %ebx; add %r15, %rbx; jmp *%rax') | |
120 | |
121 # The mask and the jump must be adjacent. | |
122 TestCase(accept=False, asm='and $~31, %eax; nop; add %r15, %rax; jmp *%rax') | |
123 TestCase(accept=False, asm='and $~31, %eax; add %r15, %rax; nop; jmp *%rax') | |
124 | |
125 # Jumping into the middle of the superinstruction must be rejected. | |
126 TestCase(accept=False, asm=""" | |
127 and $~31, %eax | |
128 add %r15, %rax | |
129 label: | |
130 jmp *%rax | |
131 jmp label | |
132 """) | |
133 TestCase(accept=False, asm=""" | |
134 and $~31, %eax | |
135 label: | |
136 add %r15, %rax | |
137 jmp *%rax | |
138 jmp label | |
139 """) | |
140 | |
141 # Read-only access to special registers is allowed. | |
142 TestCase(accept=True, asm='push %rax') | |
143 TestCase(accept=True, asm='push %rbp') | |
144 TestCase(accept=True, asm='push %rsp') | |
145 TestCase(accept=True, asm='push %r15') | |
146 TestCase(accept=True, asm='mov %rsp, %rax') | |
147 # But write access is not. | |
148 TestCase(accept=True, asm='pop %rax') | |
149 TestCase(accept=False, asm='pop %rbp') | |
150 TestCase(accept=False, asm='pop %rsp') | |
151 TestCase(accept=False, asm='pop %r15') | |
152 | |
153 # Memory accesses. | |
154 TestCase(accept=True, asm=""" | |
155 mov %eax, %eax | |
156 mov (%r15, %rax), %ebx | |
157 """) | |
158 # Test for a top-bit-set register. | |
159 TestCase(accept=True, asm=""" | |
160 mov %r12d, %r12d | |
161 mov (%r15, %r12), %ebx | |
162 """) | |
163 # Check %edi and %esi because the first 'mov' also begins superinstructions. | |
164 TestCase(accept=True, asm=""" | |
165 mov %edi, %edi | |
166 mov (%r15, %rdi), %ebx | |
167 """) | |
168 TestCase(accept=True, asm=""" | |
169 mov %esi, %esi | |
170 mov (%r15, %rsi), %ebx | |
171 """) | |
172 # Check mask on its own. | |
173 TestCase(accept=True, asm=""" | |
174 mov %eax, %eax | |
175 """) | |
176 TestCase(accept=False, asm=""" | |
177 mov (%r15, %rax), %ebx | |
178 """) | |
179 TestCase(accept=False, asm=""" | |
180 mov %eax, %eax | |
181 label: | |
182 mov (%r15, %rax), %ebx | |
183 jmp label | |
184 """) | |
185 | |
186 # Check that post-conditions do not leak from a superinstruction. To | |
187 # share DFT states, the first instruction of the nacljmp, "and $~31, | |
188 # %eax", records a post-condition, just as when it is used on its own. | |
189 # Although the code below is safe, we don't really want the | |
190 # post-condition to leak through. | |
191 TestCase(accept=False, asm=""" | |
192 and $~31, %eax | |
193 add %r15, %rax | |
194 jmp *%rax | |
195 // %rax should not be regarded as zero-extended here. | |
196 mov (%r15, %rax), %ebx | |
197 """) | |
198 TestCase(accept=False, asm=""" | |
199 mov %edi, %edi | |
200 lea (%r15, %rdi), %rdi | |
201 rep stos %al, %es:(%rdi) | |
202 // %rdi should not be regarded as zero-extended here. | |
203 mov (%r15, %rdi), %ebx | |
204 """) | |
205 TestCase(accept=False, asm=""" | |
206 mov %esi, %esi | |
207 lea (%r15, %rsi), %rsi | |
208 mov %edi, %edi | |
209 lea (%r15, %rdi), %rdi | |
210 rep movsb %ds:(%rsi), %es:(%rdi) | |
211 // %rsi should not be regarded as zero-extended here. | |
212 mov (%r15, %rsi), %ebx | |
213 """) | |
214 | |
215 # Non-%r15-based memory accesses. | |
216 TestCase(accept=True, asm='mov 0x1234(%rip), %eax') | |
217 TestCase(accept=True, asm='mov 0x1234(%rsp), %eax') | |
218 TestCase(accept=True, asm='mov 0x1234(%rbp), %eax') | |
219 TestCase(accept=False, asm='mov 0x1234(%rsp, %rbx), %eax') | |
220 TestCase(accept=False, asm='mov 0x1234(%rbp, %rbx), %eax') | |
221 TestCase(accept=True, asm='mov %ebx, %ebx; mov 0x1234(%rsp, %rbx), %eax') | |
222 TestCase(accept=True, asm='mov %ebx, %ebx; mov 0x1234(%rbp, %rbx), %eax') | |
223 | |
224 # 'lea' is not a memory access. | |
225 TestCase(accept=True, asm='lea (%rbx, %rcx, 4), %rax') | |
226 | |
227 # Stack operations. | |
228 TestCase(accept=True, asm='mov %rsp, %rbp') | |
229 TestCase(accept=True, asm='mov %rbp, %rsp') | |
230 TestCase(accept=True, asm=""" | |
231 add $8, %ebp | |
232 add %r15, %rbp | |
233 """) | |
234 TestCase(accept=False, asm=""" | |
235 add $8, %ebp | |
236 label: | |
237 add %r15, %rbp | |
238 jmp label | |
239 """) | |
240 # A stack fixup on its own is not allowed. | |
241 TestCase(accept=False, asm='add %r15, %rbp') | |
242 TestCase(accept=False, asm='add %r15, %rsp') | |
243 TestCase(accept=False, asm='add %r15, %r15') | |
244 | |
245 # Sandboxing is not required on prefetch instructions. | |
246 TestCase(accept=True, asm='prefetchnta (%rax)') | |
247 | |
248 | |
249 def Main(): | |
250 for test_case in test_cases: | |
251 test_case() | |
252 print 'PASS' | |
253 | |
254 | |
255 if __name__ == '__main__': | |
256 Main() | |
OLD | NEW |