blob: 2053cd5d78e5935658e1fecec074b258ba1d75ba [file] [log] [blame]
Kevin O'Connor35f42dc2012-03-05 17:45:55 -05001#!/usr/bin/env python
2# Work around x86emu bugs by replacing problematic instructions.
3#
4# Copyright (C) 2012 Kevin O'Connor <kevin@koconnor.net>
5#
6# This file may be distributed under the terms of the GNU GPLv3 license.
7
8# The x86emu code widely used in Linux distributions when running Xorg
9# in vesamode is known to have issues with "retl", "leavel", "entryl",
Kevin O'Connor0b2165d2015-04-09 17:20:16 -040010# "leal", and some variants of "calll". This code modifies those
11# instructions that are known to be generated by gcc to avoid
Kevin O'Connor35f42dc2012-03-05 17:45:55 -050012# triggering the x86emu bugs.
13
14# It is also known that the Windows vgabios emulator has issues with
15# addressing negative offsets to the %esp register. That has been
Kevin O'Connorf9c30722012-12-07 12:23:27 -050016# worked around by not using the gcc parameter "-fomit-frame-pointer"
Kevin O'Connor35f42dc2012-03-05 17:45:55 -050017# when compiling.
18
Kevin O'Connor0b2165d2015-04-09 17:20:16 -040019import sys, re
20
21# leal parameter regex - example string: -3(%edx,%eax,8), %eax
22re_leal = re.compile(
23 r'^\s*(?P<offset>[^(]*?)\s*'
24 r'\(\s*(?P<base>[^,)]*?)\s*(?:,\s*(?P<index>[^,)]*?)\s*)?'
25 r'(?:,\s*(?P<scale>[^,)]*?)\s*)?\)\s*'
26 r',\s*(?P<dest>.*?)\s*$')
27
28# Find an alternate set of instructions for a given "leal" instruction
29def handle_leal(sline):
30 m = re_leal.match(sline[5:])
31 if m is None or m.group('index') == '%esp':
32 print("Unable to fixup leal instruction: %s" % (sline,))
33 sys.exit(-1)
34 offset, base, index, scale, dest = m.group(
35 'offset', 'base', 'index', 'scale', 'dest')
36 if dest == '%esp':
37 # If destination is %esp then just use 16bit leaw instead
38 return 'leaw %s\n' % (sline[5:].replace('%e', '%'),)
39 if not scale:
40 scale = '1'
41 scale = {1: 0, 2: 1, 4: 2, 8: 3}[int(scale, 0)]
42 # Try to rearrange arguments to simplify 'base' (to improve code gen)
43 if not scale and base == index:
44 base, index, scale = '', index, 1
45 elif not index or (not scale and base in (dest, '%esp') and index != dest):
46 base, index, scale = index, base, 0
47 # Produce instructions to calculate "leal"
48 insns = ['pushfw']
49 if base != dest:
50 # Calculate "leal" directly in dest register
51 if index != dest:
52 insns.insert(0, 'movl %s, %s' % (index, dest))
53 if scale:
54 insns.append('shll $%d, %s' % (scale, dest))
55 if base:
56 if base == '%esp':
57 offset += '+2'
58 insns.append('addl %s, %s' % (base, dest))
59 elif base == index:
60 # Use "imull" method
61 insns.append('imull $%d, %s' % ((1<<scale)+1, dest))
62 else:
63 # Backup/restore index register and do scaling in index register
64 insns.append('pushl %s' % (index,))
65 insns.append('shll $%d, %s' % (scale, index))
66 insns.append('addl %s, %s' % (index, dest))
67 insns.append('popl %s' % (index,))
68 if offset and offset != '0':
69 insns.append('addl $%s, %s' % (offset, dest))
70 insns.append('popfw\n')
71 return ' ; '.join(insns)
Kevin O'Connor35f42dc2012-03-05 17:45:55 -050072
73def main():
74 infilename, outfilename = sys.argv[1:]
Johannes Krampf19f789b2014-01-19 16:03:49 +010075 infile = open(infilename, 'r')
Kevin O'Connor35f42dc2012-03-05 17:45:55 -050076 out = []
77 for line in infile:
78 sline = line.strip()
79 if sline == 'ret':
80 out.append('retw $2\n')
81 elif sline == 'leave':
82 out.append('movl %ebp, %esp ; popl %ebp\n')
Kevin O'Connor9332f9b2013-11-30 12:52:44 -050083 elif sline.startswith('call'):
84 out.append('pushw %ax ; callw' + sline[4:] + '\n')
Kevin O'Connor0b2165d2015-04-09 17:20:16 -040085 elif sline.startswith('leal'):
86 out.append(handle_leal(sline))
87 #print("-> %s\n %s" % (sline, out[-1].strip()))
Kevin O'Connor35f42dc2012-03-05 17:45:55 -050088 else:
89 out.append(line)
90 infile.close()
Johannes Krampf19f789b2014-01-19 16:03:49 +010091 outfile = open(outfilename, 'w')
Kevin O'Connor35f42dc2012-03-05 17:45:55 -050092 outfile.write(''.join(out))
93 outfile.close()
94
95if __name__ == '__main__':
96 main()