VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-3-high-lea64.py@ 103068

Last change on this file since 103068 was 102278, checked in by vboxsync, 13 months ago

ValKit/bs3-cpu-basic-3: A couple of fixes. bugref:10371

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 19.9 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: bs3-cpu-basic-3-high-lea64.py 102278 2023-11-23 15:44:17Z vboxsync $
4# pylint: disable=invalid-name
5
6"""
7Generates the assembly body of the 64-bit lea testcase.
8
9Nasm consumes too much memory (>19GB) doing this via the preprocessor, it also
10takes its good time about it. This script takes 2-3 seconds and nasm only
11consumes a few hundred MB of memory processing it (takes some 40 seconds, though).
12"""
13
14from __future__ import print_function;
15
16__copyright__ = \
17"""
18Copyright (C) 2023 Oracle and/or its affiliates.
19
20This file is part of VirtualBox base platform packages, as
21available from https://www.virtualbox.org.
22
23This program is free software; you can redistribute it and/or
24modify it under the terms of the GNU General Public License
25as published by the Free Software Foundation, in version 3 of the
26License.
27
28This program is distributed in the hope that it will be useful, but
29WITHOUT ANY WARRANTY; without even the implied warranty of
30MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
31General Public License for more details.
32
33You should have received a copy of the GNU General Public License
34along with this program; if not, see <https://www.gnu.org/licenses>.
35
36The contents of this file may alternatively be used under the terms
37of the Common Development and Distribution License Version 1.0
38(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
39in the VirtualBox distribution, in which case the provisions of the
40CDDL are applicable instead of those of the GPL.
41
42You may elect to license modified versions of this file under the
43terms and conditions of either the GPL or the CDDL or both.
44
45SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
46"""
47__version__ = "$Revision: 102278 $"
48
49# Standard python imports.
50import random;
51import sys;
52
53g_kasRegNames = [
54 'rax',
55 'rcx',
56 'rdx',
57 'rbx',
58 'rsp',
59 'rbp',
60 'rsi',
61 'rdi',
62 'r8',
63 'r9',
64 'r10',
65 'r11',
66 'r12',
67 'r13',
68 'r14',
69 'r15',
70];
71
72g_kaiRegValues = [
73 0x1111111111111110,
74 0x2222222222222202,
75 0x3333333333333033,
76 0x4444444444440444,
77 0x58595a5d51525356,
78 0x5555555555555551,
79 0x6666666666666616,
80 0x7777777777777177,
81 0x8888888888881888,
82 0x9999999999999992,
83 0xaaaaaaaaaaaaaa2a,
84 0xbbbbbbbbbbbbb2bb,
85 0xcccccccccccc2ccc,
86 0xddddddddddddddd3,
87 0xeeeeeeeeeeeeee3e,
88 0xfffffffffffff3ff,
89];
90
91def x86ModRmMake(iMod, iReg, iRm):
92 """ See X86_MODRM_MAKE. """
93 return (iMod << 6) | ((iReg & 7) << 3) | (iRm & 7);
94
95def x86SibMake(iBase, iIndex, cShift):
96 """ X86_SIB_MAKE(iBase & 7, iIndex & 7, cShift) """
97 return (cShift << 6) | ((iIndex & 7) << 3) | (iBase & 7);
98
99def x86RexW3(iBase, iIndex, iDstReg):
100 # db X86_OP_REX_W | ((iBase & 8) >> 3) | ((iIndex & 8) >> 2) | ((iDstReg & 8) >> 1)
101 return 0x48 | ((iBase & 8) >> 3) | ((iIndex & 8) >> 2) | ((iDstReg & 8) >> 1);
102
103def x86Rex3(iBase, iIndex, iDstReg):
104 # db X86_OP_REX | ((iBase & 8) >> 3) | ((iIndex & 8) >> 2) | ((iDstReg & 8) >> 1)
105 return 0x40 | ((iBase & 8) >> 3) | ((iIndex & 8) >> 2) | ((iDstReg & 8) >> 1);
106
107def generateTraceAndLoad(fLoadRsp, fTracing):
108 """ Loads registers and traces current position if requested. """
109 if fTracing:
110 asRet = ['mov dword [rel BS3_DATA_NM(g_bs3CpuBasic3_lea_trace)], $',];
111 else:
112 asRet = [];
113 asRet.append('call .load_regs');
114 if fLoadRsp:
115 asRet.append('mov rsp, %#x' % (g_kaiRegValues[4], ));
116 return asRet;
117
118def cenerateCompareAndCheckSib(sDstRegName, iValue, fRestoreRsp):
119 """ Checks that sDstRegName contains iValue, executing int3 if it doesn't and restoring RSP first if requested. """
120 if -0x80000000 <= iValue <= 0x7fffffff:
121 asRet = [
122 'cmp %s, %#x' % (sDstRegName, iValue),
123 ];
124 elif sDstRegName != 'rax':
125 asRet = [
126 'mov rax, %#x' % (iValue,),
127 'cmp %s, rax' % (sDstRegName,),
128 ];
129 else:
130 asRet = [
131 'mov rcx, %#x' % (iValue),
132 'cmp rax, rcx',
133 ];
134 if fRestoreRsp:
135 asRet += [
136 'mov rdx, rsp',
137 'mov rsp, [rel BS3_DATA_NM(g_bs3CpuBasic3_lea_rsp)]',
138 ];
139 asRet += [
140 'jz $+3',
141 'int3'
142 ];
143 return asRet;
144
145def generateCompareAndCheckModRm(sDstRegName, iValue, sValue, fRestoreRsp):
146 """
147 Checks that sDstRegName contains iValue or sValue if not None,
148 executing int3 if it doesn't and restoring RSP first if requested.
149 """
150 if sValue:
151 asRet = [
152 'cmp %s, %s' % (sDstRegName, sValue),
153 ];
154 elif -0x80000000 <= iValue <= 0x7fffffff:
155 asRet = [
156 'cmp %s, %#x' % (sDstRegName, iValue),
157 ];
158 elif sDstRegName != 'rax':
159 asRet = [
160 'mov rax, %#x' % (iValue,),
161 'cmp %s, rax' % (sDstRegName,),
162 ];
163 else:
164 asRet = [
165 'mov rcx, %#x' % (iValue),
166 'cmp rax, rcx',
167 ];
168 if fRestoreRsp:
169 asRet += [
170 'mov rdx, rsp',
171 'mov rsp, [rel BS3_DATA_NM(g_bs3CpuBasic3_lea_rsp)]',
172 ];
173 asRet += [
174 'jz $+3',
175 'int3'
176 ];
177 return asRet;
178
179def generateDispSib(iValue, iMod, iBase):
180 """ Generates the displacement part of the LEA instruction for the SIB variant. """
181 if iMod == 1: #X86_MOD_MEM1:
182 iDisp = random.randint(-128, 127);
183 return iValue + iDisp, ['db %d' % (iDisp,),];
184 if iMod == 2 or (iMod == 0 and (iBase & 7) == 5):
185 iDisp = random.randint(-0x80000000, 0x7fffffff);
186 return iValue + iDisp, ['dd %d' % (iDisp,),];
187 return iValue, [];
188
189def generateDispModRm(iValue, iMod, iMemReg, iLabelVar, f16Bit = False):
190 """ Generates the displacement part of the LEA instruction for the non-SIB variant. """
191 if iMod == 1: #X86_MOD_MEM1
192 iDisp = random.randint(-128, 127);
193 return iValue + iDisp, None, ['db %d' % (iDisp,),];
194 if iMod == 0 and (iMemReg & 7) == 5:
195 if f16Bit:
196 # Generate a known 16-bit value by trickery as we the iDstReg value is mixed.
197 # ASSUMES Bs3Text16 is 64KB aligned in the high DLL...
198 iValue = random.randint(0, 0x7fff);
199 return iValue, None, ['dd _Bs3Text16_StartOfSegment - $ - 4 + %d wrt BS3FLAT' % (iValue,),];
200 if iLabelVar & 1:
201 return iValue, '.test_label wrt BS3FLAT', ['dd .test_label - $ - 4',];
202 return iValue, '.load_regs wrt BS3FLAT', ['dd .load_regs - $ - 4',];
203 if iMod == 2: #X86_MOD_MEM4
204 iDisp = random.randint(-0x80000000, 0x7fffffff);
205 return iValue + iDisp, None, ['dd %d' % (iDisp,),];
206 return iValue, None, [];
207
208def generateLea64(oOut): # pylint: disable=too-many-statements
209 fTracing = False;
210
211 #
212 # Loop thru all the modr/m memory encodings.
213 #
214 asLines = [];
215 for iMod in range(3):
216 for iDstReg in range(16):
217 sDstReg_Name = g_kasRegNames[iDstReg];
218 iDstReg_Value = g_kaiRegValues[iDstReg];
219 for iMemReg in range(16):
220 if (iMemReg & 7) == 4:
221 #
222 # SIB.
223 #
224 for iBase in range(16):
225 if (iBase & 7) == 5 and iMod == 0:
226 iBase_Value = 0
227 else:
228 iBase_Value = g_kaiRegValues[iBase];
229
230 for iIndex in range(16):
231 if iIndex == 4:
232 iIndex_Value = 0;
233 else:
234 iIndex_Value = g_kaiRegValues[iIndex];
235
236 for cShift in range(4):
237 fLoadRestoreRsp = iBase == 4 or iDstReg == 4;
238
239 #
240 # LEA+SIB w/ 64-bit operand size and 64-bit address size.
241 #
242 asLines.extend(generateTraceAndLoad(fLoadRestoreRsp, fTracing));
243
244 # lea
245 iValue = iBase_Value + (iIndex_Value << cShift)
246 asLines.append('db %#x, 8dh, %#x, %#x'
247 % (x86RexW3(iBase, iIndex, iDstReg), x86ModRmMake(iMod, iDstReg, iMemReg),
248 x86SibMake(iBase, iIndex, cShift),));
249 iValue, asAdd = generateDispSib(iValue, iMod, iBase);
250 asLines.extend(asAdd);
251 iValue &= 0xffffffffffffffff;
252
253 # cmp iDstReg, iValue + jz + int3
254 asLines.extend(cenerateCompareAndCheckSib(sDstReg_Name, iValue, fLoadRestoreRsp));
255
256
257 #
258 # LEA+SIB w/ 64-bit operand size and 32-bit address size.
259 #
260 asLines.extend(generateTraceAndLoad(fLoadRestoreRsp, fTracing));
261
262 # lea w/ X86_OP_PRF_SIZE_ADDR
263 iValue = iBase_Value + (iIndex_Value << cShift)
264 asLines.append('db 067h, %#x, 8dh, %#x, %#x'
265 % (x86RexW3(iBase, iIndex, iDstReg), x86ModRmMake(iMod, iDstReg, iMemReg),
266 x86SibMake(iBase, iIndex, cShift),));
267 iValue, asAdd = generateDispSib(iValue, iMod, iBase);
268 asLines.extend(asAdd);
269 iValue &= 0xffffffff;
270
271 # cmp iDstReg, iValue + jz + int3
272 asLines.extend(cenerateCompareAndCheckSib(sDstReg_Name, iValue, fLoadRestoreRsp));
273
274
275 #
276 # LEA+SIB w/ 32-bit operand size and 64-bit address size.
277 #
278 asLines.extend(generateTraceAndLoad(fLoadRestoreRsp, fTracing));
279
280 # lea
281 iValue = iBase_Value + (iIndex_Value << cShift);
282 if (iBase | iIndex | iDstReg) & 8:
283 asLines.append('db %#x' % (x86Rex3(iBase, iIndex, iDstReg),));
284 asLines.append('db 8dh, %#x, %#x'
285 % (x86ModRmMake(iMod, iDstReg, iMemReg), x86SibMake(iBase, iIndex, cShift),));
286 iValue, asAdd = generateDispSib(iValue, iMod, iBase);
287 asLines.extend(asAdd);
288 iValue &= 0xffffffff;
289
290 # cmp iDstReg, iValue + jz + int3
291 asLines.extend(cenerateCompareAndCheckSib(sDstReg_Name, iValue, fLoadRestoreRsp));
292
293
294 #
295 # LEA+SIB w/ 32-bit operand size and 32-bit address size.
296 #
297 asLines.extend(generateTraceAndLoad(fLoadRestoreRsp, fTracing));
298
299 # lea
300 iValue = iBase_Value + (iIndex_Value << cShift);
301 asLines.append('db 067h'); # X86_OP_PRF_SIZE_ADDR
302 if (iBase | iIndex | iDstReg) & 8:
303 asLines.append('db %#x' % (x86Rex3(iBase, iIndex, iDstReg),));
304 asLines.append('db 8dh, %#x, %#x'
305 % (x86ModRmMake(iMod, iDstReg, iMemReg), x86SibMake(iBase, iIndex, cShift),));
306 iValue, asAdd = generateDispSib(iValue, iMod, iBase);
307 asLines.extend(asAdd);
308 iValue &= 0xffffffff;
309
310 # cmp iDstReg, iValue + jz + int3
311 asLines.extend(cenerateCompareAndCheckSib(sDstReg_Name, iValue, fLoadRestoreRsp));
312
313
314 #
315 # LEA+SIB w/ 16-bit operand size and 64-bit address size.
316 #
317 asLines.extend(generateTraceAndLoad(fLoadRestoreRsp, fTracing));
318
319 # lea
320 iValue = iBase_Value + (iIndex_Value << cShift);
321 asLines.append('db 66h'); # X86_OP_PRF_SIZE_OP
322 if (iBase | iIndex | iDstReg) & 8:
323 asLines.append('db %#x' % (x86Rex3(iBase, iIndex, iDstReg),));
324 asLines.append('db 8dh, %#x, %#x'
325 % (x86ModRmMake(iMod, iDstReg, iMemReg), x86SibMake(iBase, iIndex, cShift),));
326 iValue, asAdd = generateDispSib(iValue, iMod, iBase);
327 asLines.extend(asAdd);
328 iValue = (iValue & 0xffff) | (iDstReg_Value & 0xffffffffffff0000);
329
330 # cmp iDstReg, iValue + jz + int3
331 asLines.extend(cenerateCompareAndCheckSib(sDstReg_Name, iValue, fLoadRestoreRsp));
332
333 #
334 # LEA+SIB w/ 16-bit operand size and 32-bit address size.
335 #
336 asLines.extend(generateTraceAndLoad(fLoadRestoreRsp, fTracing));
337
338 # lea
339 iValue = iBase_Value + (iIndex_Value << cShift);
340 if cShift & 2:
341 asLines.append('db 066h, 067h'); # X86_OP_PRF_SIZE_OP, X86_OP_PRF_SIZE_ADDR
342 else:
343 asLines.append('db 067h, 066h'); # X86_OP_PRF_SIZE_ADDR, X86_OP_PRF_SIZE_OP
344 if (iBase | iIndex | iDstReg) & 8:
345 asLines.append('db %#x' % (x86Rex3(iBase, iIndex, iDstReg),));
346 asLines.append('db 8dh, %#x, %#x'
347 % (x86ModRmMake(iMod, iDstReg, iMemReg), x86SibMake(iBase, iIndex, cShift),));
348 iValue, asAdd = generateDispSib(iValue, iMod, iBase);
349 asLines.extend(asAdd);
350 iValue = (iValue & 0xffff) | (iDstReg_Value & 0xffffffffffff0000);
351
352 # cmp iDstReg, iValue + jz + int3
353 asLines.extend(cenerateCompareAndCheckSib(sDstReg_Name, iValue, fLoadRestoreRsp));
354
355 else: # !SIB
356 #
357 # Plain lea reg, [reg] with disp according to iMod,
358 # or lea reg, [disp32] if iMemReg == 5 && iMod == 0.
359 #
360 if (iMemReg & 7) == 5 and iMod == 0:
361 iMemReg_Value = 0;
362 else:
363 iMemReg_Value = g_kaiRegValues[iMemReg];
364
365 fLoadRestoreRsp = iDstReg == 4;
366
367 #
368 # 64-bit operand and address size first.
369 #
370 asLines.extend(generateTraceAndLoad(fLoadRestoreRsp, fTracing));
371
372 # lea
373 asLines.append('db %#x, 8dh, %#x'
374 % (x86RexW3(iMemReg, 0, iDstReg), x86ModRmMake(iMod, iDstReg, iMemReg),));
375 iValue, sValue, asAdd = generateDispModRm(iMemReg_Value, iMod, iMemReg, 0);
376 asLines.extend(asAdd);
377 iValue &= 0xffffffffffffffff;
378
379 # cmp iDstReg, iValue + jz + int3
380 asLines.extend(generateCompareAndCheckModRm(sDstReg_Name, iValue, sValue, fLoadRestoreRsp));
381
382
383 #
384 # 64-bit operand and 32-bit address size.
385 #
386 asLines.extend(generateTraceAndLoad(fLoadRestoreRsp, fTracing));
387
388 # lea w/ X86_OP_PRF_SIZE_ADDR
389 asLines.append('db 067h, %#x, 8dh, %#x'
390 % (x86RexW3(iMemReg, 0, iDstReg), x86ModRmMake(iMod, iDstReg, iMemReg),));
391 iValue, sValue, asAdd = generateDispModRm(iMemReg_Value, iMod, iMemReg, 1);
392 asLines.extend(asAdd);
393 iValue &= 0x00000000ffffffff;
394
395 # cmp iDstReg, iValue + jz + int3
396 asLines.extend(generateCompareAndCheckModRm(sDstReg_Name, iValue, sValue, fLoadRestoreRsp));
397
398
399 #
400 # 32-bit operand and 64-bit address size.
401 #
402 asLines.extend(generateTraceAndLoad(fLoadRestoreRsp, fTracing));
403
404 # lea iValue = iMemReg_Value;
405 iValue = iMemReg_Value;
406 if iDstReg >= 8 or iMemReg >= 8:
407 asLines.append('db %#x' % (x86Rex3(iMemReg, 0, iDstReg),));
408 asLines.append('db 8dh, %#x' % (x86ModRmMake(iMod, iDstReg, iMemReg),));
409 iValue, sValue, asAdd = generateDispModRm(iMemReg_Value, iMod, iMemReg, 2);
410 asLines.extend(asAdd);
411 iValue &= 0x00000000ffffffff;
412
413 # cmp iDstReg, iValue + jz + int3
414 asLines.extend(generateCompareAndCheckModRm(sDstReg_Name, iValue, sValue, fLoadRestoreRsp));
415
416
417 #
418 # 16-bit operand and 64-bit address size.
419 #
420 asLines.extend(generateTraceAndLoad(fLoadRestoreRsp, fTracing));
421
422 # lea
423 asLines.append('db 066h'); # X86_OP_PRF_SIZE_OP
424 if iDstReg >= 8 or iMemReg >= 8:
425 asLines.append('db %#x' % (x86Rex3(iMemReg, 0, iDstReg),));
426 asLines.append('db 8dh, %#x' % (x86ModRmMake(iMod, iDstReg, iMemReg),));
427 iValue, sValue, asAdd = generateDispModRm(iMemReg_Value, iMod, iMemReg, 0, True);
428 asLines.extend(asAdd);
429 iValue = (iValue & 0xffff) | (iDstReg_Value & 0xffffffffffff0000);
430
431 # cmp iDstReg, iValue
432 asLines.extend(generateCompareAndCheckModRm(sDstReg_Name, iValue, sValue, fLoadRestoreRsp));
433
434 #
435 # 16-bit operand and 32-bit address size.
436 #
437 asLines.extend(generateTraceAndLoad(fLoadRestoreRsp, fTracing));
438
439 # lea
440 if random.randint(0, 1):
441 asLines.append('db 066h,067h'); # X86_OP_PRF_SIZE_OP, X86_OP_PRF_SIZE_ADDR
442 else:
443 asLines.append('db 067h,066h'); # X86_OP_PRF_SIZE_ADDR, X86_OP_PRF_SIZE_OP
444 if iDstReg >= 8 or iMemReg >= 8:
445 asLines.append('db %#x' % (x86Rex3(iMemReg, 0, iDstReg),));
446 asLines.append('db 8dh, %#x' % (x86ModRmMake(iMod, iDstReg, iMemReg),));
447 iValue, sValue, asAdd = generateDispModRm(iMemReg_Value, iMod, iMemReg, 0, True);
448 asLines.extend(asAdd);
449 iValue = (iValue & 0xffff) | (iDstReg_Value & 0xffffffffffff0000);
450
451 # cmp iDstReg, iValue
452 asLines.extend(generateCompareAndCheckModRm(sDstReg_Name, iValue, sValue, fLoadRestoreRsp));
453
454 oOut.write('\n'.join(asLines));
455 return 0;
456
457def main(asArgs):
458 if len(asArgs) != 2 or asArgs[1][0] == '-':
459 print('bs3-cpu-basic-3-high-lea64.py: syntax error!\n', file = sys.stderr);
460 return 2;
461 with open(asArgs[1], 'w', encoding = 'utf-8') as oOut:
462 generateLea64(oOut);
463 return 0;
464
465if __name__ == '__main__':
466 sys.exit(main(sys.argv));
467
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette