Kevin O'Connor | 35f42dc | 2012-03-05 17:45:55 -0500 | [diff] [blame] | 1 | #!/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'Connor | 0b2165d | 2015-04-09 17:20:16 -0400 | [diff] [blame] | 10 | # "leal", and some variants of "calll". This code modifies those |
| 11 | # instructions that are known to be generated by gcc to avoid |
Kevin O'Connor | 35f42dc | 2012-03-05 17:45:55 -0500 | [diff] [blame] | 12 | # 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'Connor | f9c3072 | 2012-12-07 12:23:27 -0500 | [diff] [blame] | 16 | # worked around by not using the gcc parameter "-fomit-frame-pointer" |
Kevin O'Connor | 35f42dc | 2012-03-05 17:45:55 -0500 | [diff] [blame] | 17 | # when compiling. |
| 18 | |
Kevin O'Connor | 0b2165d | 2015-04-09 17:20:16 -0400 | [diff] [blame] | 19 | import sys, re |
| 20 | |
| 21 | # leal parameter regex - example string: -3(%edx,%eax,8), %eax |
| 22 | re_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 |
| 29 | def 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'Connor | 35f42dc | 2012-03-05 17:45:55 -0500 | [diff] [blame] | 72 | |
| 73 | def main(): |
| 74 | infilename, outfilename = sys.argv[1:] |
Johannes Krampf | 19f789b | 2014-01-19 16:03:49 +0100 | [diff] [blame] | 75 | infile = open(infilename, 'r') |
Kevin O'Connor | 35f42dc | 2012-03-05 17:45:55 -0500 | [diff] [blame] | 76 | 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'Connor | 9332f9b | 2013-11-30 12:52:44 -0500 | [diff] [blame] | 83 | elif sline.startswith('call'): |
| 84 | out.append('pushw %ax ; callw' + sline[4:] + '\n') |
Kevin O'Connor | 0b2165d | 2015-04-09 17:20:16 -0400 | [diff] [blame] | 85 | elif sline.startswith('leal'): |
| 86 | out.append(handle_leal(sline)) |
| 87 | #print("-> %s\n %s" % (sline, out[-1].strip())) |
Kevin O'Connor | 35f42dc | 2012-03-05 17:45:55 -0500 | [diff] [blame] | 88 | else: |
| 89 | out.append(line) |
| 90 | infile.close() |
Johannes Krampf | 19f789b | 2014-01-19 16:03:49 +0100 | [diff] [blame] | 91 | outfile = open(outfilename, 'w') |
Kevin O'Connor | 35f42dc | 2012-03-05 17:45:55 -0500 | [diff] [blame] | 92 | outfile.write(''.join(out)) |
| 93 | outfile.close() |
| 94 | |
| 95 | if __name__ == '__main__': |
| 96 | main() |