--- /dev/null
+# @file ConvertMasmToNasm.py\r
+# This script assists with conversion of MASM assembly syntax to NASM\r
+#\r
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+\r
+#\r
+# Import Modules\r
+#\r
+import os.path\r
+import re\r
+import StringIO\r
+import subprocess\r
+import sys\r
+from optparse import OptionParser\r
+\r
+\r
+class UnsupportedConversion(Exception):\r
+ pass\r
+\r
+\r
+class NoSourceFile(Exception):\r
+ pass\r
+\r
+\r
+class UnsupportedArch(Exception):\r
+ unsupported = ('aarch64', 'arm', 'ebc', 'ipf')\r
+\r
+\r
+class CommonUtils:\r
+\r
+ # Version and Copyright\r
+ VersionNumber = "0.01"\r
+ __version__ = "%prog Version " + VersionNumber\r
+ __copyright__ = "Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved."\r
+ __usage__ = "%prog [options] source.asm [destination.nasm]"\r
+\r
+ def __init__(self, clone=None):\r
+ if clone is None:\r
+ (self.Opt, self.Args) = self.ProcessCommandLine()\r
+ else:\r
+ (self.Opt, self.Args) = (clone.Opt, clone.Args)\r
+\r
+ self.unsupportedSyntaxSeen = False\r
+ self.src = self.Args[0]\r
+ assert(os.path.exists(self.src))\r
+ self.dirmode = os.path.isdir(self.src)\r
+ srcExt = os.path.splitext(self.src)[1]\r
+ assert (self.dirmode or srcExt != '.nasm')\r
+ self.infmode = not self.dirmode and srcExt == '.inf'\r
+ self.diff = self.Opt.diff\r
+ self.git = self.Opt.git\r
+ self.force = self.Opt.force\r
+\r
+ if clone is None:\r
+ self.rootdir = os.getcwd()\r
+ self.DetectGit()\r
+ else:\r
+ self.rootdir = clone.rootdir\r
+ self.gitdir = clone.gitdir\r
+ self.gitemail = clone.gitemail\r
+\r
+ def ProcessCommandLine(self):\r
+ Parser = OptionParser(description=self.__copyright__,\r
+ version=self.__version__,\r
+ prog=sys.argv[0],\r
+ usage=self.__usage__\r
+ )\r
+ Parser.add_option("-q", "--quiet", action="store_true", type=None,\r
+ help="Disable all messages except FATAL ERRORS.")\r
+ Parser.add_option("--git", action="store_true", type=None,\r
+ help="Use git to create commits for each file converted")\r
+ Parser.add_option("--diff", action="store_true", type=None,\r
+ help="Show diff of conversion")\r
+ Parser.add_option("-f", "--force", action="store_true", type=None,\r
+ help="Force conversion even if unsupported")\r
+\r
+ (Opt, Args) = Parser.parse_args()\r
+\r
+ if not Opt.quiet:\r
+ print self.__copyright__\r
+ Parser.print_version()\r
+\r
+ return (Opt, Args)\r
+\r
+ def RootRelative(self, path):\r
+ result = path\r
+ if result.startswith(self.rootdir):\r
+ result = result[len(self.rootdir):]\r
+ while len(result) > 0 and result[0] in '/\\':\r
+ result = result[1:]\r
+ return result\r
+\r
+ def MatchAndSetMo(self, regexp, string):\r
+ self.mo = regexp.match(string)\r
+ return self.mo is not None\r
+\r
+ def SearchAndSetMo(self, regexp, string):\r
+ self.mo = regexp.search(string)\r
+ return self.mo is not None\r
+\r
+ def ReplacePreserveSpacing(self, string, find, replace):\r
+ if len(find) >= len(replace):\r
+ padded = replace + (' ' * (len(find) - len(replace)))\r
+ return string.replace(find, padded)\r
+ elif find.find(replace) >= 0:\r
+ return string.replace(find, replace)\r
+ else:\r
+ lenDiff = len(replace) - len(find)\r
+ result = string\r
+ for i in range(lenDiff, -1, -1):\r
+ padded = find + (' ' * i)\r
+ result = result.replace(padded, replace)\r
+ return result\r
+\r
+ def DetectGit(self):\r
+ lastpath = os.path.realpath(self.src)\r
+ self.gitdir = None\r
+ while True:\r
+ path = os.path.split(lastpath)[0]\r
+ if path == lastpath:\r
+ return\r
+ candidate = os.path.join(path, '.git')\r
+ if os.path.isdir(candidate):\r
+ self.gitdir = candidate\r
+ self.gitemail = self.FormatGitEmailAddress()\r
+ return\r
+ lastpath = path\r
+\r
+ def FormatGitEmailAddress(self):\r
+ if not self.git or not self.gitdir:\r
+ return ''\r
+\r
+ cmd = ('git', 'config', 'user.name')\r
+ name = self.RunAndCaptureOutput(cmd).strip()\r
+ cmd = ('git', 'config', 'user.email')\r
+ email = self.RunAndCaptureOutput(cmd).strip()\r
+ if name.find(',') >= 0:\r
+ name = '"' + name + '"'\r
+ return name + ' <' + email + '>'\r
+\r
+ def RunAndCaptureOutput(self, cmd, checkExitCode=True, pipeIn=None):\r
+ if pipeIn:\r
+ subpStdin = subprocess.PIPE\r
+ else:\r
+ subpStdin = None\r
+ p = subprocess.Popen(args=cmd, stdout=subprocess.PIPE, stdin=subpStdin)\r
+ (stdout, stderr) = p.communicate(pipeIn)\r
+ if checkExitCode:\r
+ if p.returncode != 0:\r
+ print 'command:', ' '.join(cmd)\r
+ print 'stdout:', stdout\r
+ print 'stderr:', stderr\r
+ print 'return:', p.returncode\r
+ assert p.returncode == 0\r
+ return stdout\r
+\r
+ def FileUpdated(self, path):\r
+ if not self.git or not self.gitdir:\r
+ return\r
+\r
+ cmd = ('git', 'add', path)\r
+ self.RunAndCaptureOutput(cmd)\r
+\r
+ def FileAdded(self, path):\r
+ self.FileUpdated(path)\r
+\r
+ def RemoveFile(self, path):\r
+ if not self.git or not self.gitdir:\r
+ return\r
+\r
+ cmd = ('git', 'rm', path)\r
+ self.RunAndCaptureOutput(cmd)\r
+\r
+ def FileConversionFinished(self, pkg, module, src, dst):\r
+ if not self.git or not self.gitdir:\r
+ return\r
+\r
+ if not self.Opt.quiet:\r
+ print 'Committing: Conversion of', dst\r
+\r
+ prefix = ' '.join(filter(lambda a: a, [pkg, module]))\r
+ message = ''\r
+ if self.unsupportedSyntaxSeen:\r
+ message += 'ERROR! '\r
+ message += '%s: Convert %s to NASM\n' % (prefix, src)\r
+ message += '\n'\r
+ message += 'The %s script was used to convert\n' % sys.argv[0]\r
+ message += '%s to %s\n' % (src, dst)\r
+ message += '\n'\r
+ message += 'Contributed-under: TianoCore Contribution Agreement 1.0\n'\r
+ message += 'Signed-off-by: %s\n' % self.gitemail\r
+\r
+ cmd = ('git', 'commit', '-F', '-')\r
+ self.RunAndCaptureOutput(cmd, pipeIn=message)\r
+\r
+\r
+class ConvertAsmFile(CommonUtils):\r
+\r
+ def __init__(self, src, dst, clone):\r
+ CommonUtils.__init__(self, clone)\r
+ self.ConvertAsmFile(src, dst)\r
+ self.FileAdded(dst)\r
+ self.RemoveFile(src)\r
+\r
+ def ConvertAsmFile(self, inputFile, outputFile=None):\r
+ self.globals = set()\r
+ self.unsupportedSyntaxSeen = False\r
+ self.inputFilename = inputFile\r
+ if not outputFile:\r
+ outputFile = os.path.splitext(inputFile)[0] + '.nasm'\r
+ self.outputFilename = outputFile\r
+\r
+ fullSrc = os.path.realpath(inputFile)\r
+ srcParentDir = os.path.basename(os.path.split(fullSrc)[0])\r
+ maybeArch = srcParentDir.lower()\r
+ if maybeArch in UnsupportedArch.unsupported:\r
+ raise UnsupportedArch\r
+ self.ia32 = maybeArch == 'ia32'\r
+ self.x64 = maybeArch == 'x64'\r
+\r
+ self.inputFileBase = os.path.basename(self.inputFilename)\r
+ self.outputFileBase = os.path.basename(self.outputFilename)\r
+ if self.outputFilename == '-' and not self.diff:\r
+ self.output = sys.stdout\r
+ else:\r
+ self.output = StringIO.StringIO()\r
+ if not self.Opt.quiet:\r
+ dirpath, src = os.path.split(self.inputFilename)\r
+ dirpath = self.RootRelative(dirpath)\r
+ dst = os.path.basename(self.outputFilename)\r
+ print 'Converting:', dirpath, src, '->', dst\r
+ lines = open(self.inputFilename).readlines()\r
+ self.Convert(lines)\r
+ if self.outputFilename == '-':\r
+ if self.diff:\r
+ sys.stdout.write(self.output.getvalue())\r
+ self.output.close()\r
+ else:\r
+ f = open(self.outputFilename, 'wb')\r
+ f.write(self.output.getvalue())\r
+ f.close()\r
+ self.output.close()\r
+\r
+ endOfLineRe = re.compile(r'''\r
+ \s* ( ; .* )? \n $\r
+ ''',\r
+ re.VERBOSE | re.MULTILINE\r
+ )\r
+ begOfLineRe = re.compile(r'''\r
+ \s*\r
+ ''',\r
+ re.VERBOSE\r
+ )\r
+\r
+ def Convert(self, lines):\r
+ self.proc = None\r
+ self.anonLabelCount = -1\r
+ output = self.output\r
+ self.oldAsmEmptyLineCount = 0\r
+ self.newAsmEmptyLineCount = 0\r
+ for line in lines:\r
+ mo = self.begOfLineRe.search(line)\r
+ assert mo is not None\r
+ self.indent = mo.group()\r
+ lineWithoutBeginning = line[len(self.indent):]\r
+ mo = self.endOfLineRe.search(lineWithoutBeginning)\r
+ if mo is None:\r
+ endOfLine = ''\r
+ else:\r
+ endOfLine = mo.group()\r
+ oldAsm = line[len(self.indent):len(line) - len(endOfLine)]\r
+ self.originalLine = line.rstrip()\r
+ if line.strip() == '':\r
+ self.oldAsmEmptyLineCount += 1\r
+ self.TranslateAsm(oldAsm, endOfLine)\r
+ if line.strip() != '':\r
+ self.oldAsmEmptyLineCount = 0\r
+\r
+ procDeclRe = re.compile(r'''\r
+ ([\w@][\w@0-9]*) \s+\r
+ PROC\r
+ (?: \s+ NEAR | FAR )?\r
+ (?: \s+ C )?\r
+ (?: \s+ (PUBLIC | PRIVATE) )?\r
+ (?: \s+ USES ( (?: \s+ \w[\w0-9]* )+ ) )?\r
+ \s* $\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ procEndRe = re.compile(r'''\r
+ ([\w@][\w@0-9]*) \s+\r
+ ENDP\r
+ \s* $\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ varAndTypeSubRe = r' (?: [\w@][\w@0-9]* ) (?: \s* : \s* \w+ )? '\r
+ publicRe = re.compile(r'''\r
+ PUBLIC \s+\r
+ ( %s (?: \s* , \s* %s )* )\r
+ \s* $\r
+ ''' % (varAndTypeSubRe, varAndTypeSubRe),\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ varAndTypeSubRe = re.compile(varAndTypeSubRe, re.VERBOSE | re.IGNORECASE)\r
+\r
+ macroDeclRe = re.compile(r'''\r
+ ([\w@][\w@0-9]*) \s+\r
+ MACRO\r
+ \s* $\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ sectionDeclRe = re.compile(r'''\r
+ ([\w@][\w@0-9]*) \s+\r
+ ( SECTION | ENDS )\r
+ \s* $\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ externRe = re.compile(r'''\r
+ EXTE?RN \s+ (?: C \s+ )?\r
+ ([\w@][\w@0-9]*) \s* : \s* (\w+)\r
+ \s* $\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ externdefRe = re.compile(r'''\r
+ EXTERNDEF \s+ (?: C \s+ )?\r
+ ([\w@][\w@0-9]*) \s* : \s* (\w+)\r
+ \s* $\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ protoRe = re.compile(r'''\r
+ ([\w@][\w@0-9]*) \s+\r
+ PROTO\r
+ (?: \s+ .* )?\r
+ \s* $\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ defineDataRe = re.compile(r'''\r
+ ([\w@][\w@0-9]*) \s+\r
+ ( db | dw | dd | dq ) \s+\r
+ ( .*? )\r
+ \s* $\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ equRe = re.compile(r'''\r
+ ([\w@][\w@0-9]*) \s+ EQU \s+ (\S.*?)\r
+ \s* $\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ ignoreRe = re.compile(r'''\r
+ \. (?: const |\r
+ mmx |\r
+ model |\r
+ xmm |\r
+ x?list |\r
+ [3-6]86p?\r
+ ) |\r
+ page\r
+ (?: \s+ .* )?\r
+ \s* $\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ whitespaceRe = re.compile(r'\s+', re.MULTILINE)\r
+\r
+ def TranslateAsm(self, oldAsm, endOfLine):\r
+ assert(oldAsm.strip() == oldAsm)\r
+\r
+ endOfLine = endOfLine.replace(self.inputFileBase, self.outputFileBase)\r
+\r
+ oldOp = oldAsm.split()\r
+ if len(oldOp) >= 1:\r
+ oldOp = oldOp[0]\r
+ else:\r
+ oldOp = ''\r
+\r
+ if oldAsm == '':\r
+ newAsm = oldAsm\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+ elif oldOp in ('#include', ):\r
+ newAsm = oldAsm\r
+ self.EmitLine(oldAsm + endOfLine)\r
+ elif oldOp.lower() in ('end', 'title', 'text'):\r
+ newAsm = ''\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+ elif oldAsm.lower() == '@@:':\r
+ self.anonLabelCount += 1\r
+ self.EmitLine(self.anonLabel(self.anonLabelCount) + ':')\r
+ elif self.MatchAndSetMo(self.ignoreRe, oldAsm):\r
+ newAsm = ''\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+ elif oldAsm.lower() == 'ret':\r
+ for i in range(len(self.uses) - 1, -1, -1):\r
+ register = self.uses[i]\r
+ self.EmitNewContent('pop ' + register)\r
+ newAsm = 'ret'\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+ self.uses = tuple()\r
+ elif oldOp.lower() == 'lea':\r
+ newAsm = self.ConvertLea(oldAsm)\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+ elif oldAsm.lower() == 'end':\r
+ newAsm = ''\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+ self.uses = tuple()\r
+ elif self.MatchAndSetMo(self.equRe, oldAsm):\r
+ equ = self.mo.group(1)\r
+ newAsm = '%%define %s %s' % (equ, self.mo.group(2))\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+ elif self.MatchAndSetMo(self.externRe, oldAsm) or \\r
+ self.MatchAndSetMo(self.protoRe, oldAsm):\r
+ extern = self.mo.group(1)\r
+ self.NewGlobal(extern)\r
+ newAsm = 'extern ' + extern\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+ elif self.MatchAndSetMo(self.externdefRe, oldAsm):\r
+ newAsm = ''\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+ elif self.MatchAndSetMo(self.macroDeclRe, oldAsm):\r
+ newAsm = '%%macro %s 0' % self.mo.group(1)\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+ elif oldOp.lower() == 'endm':\r
+ newAsm = r'%endmacro'\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+ elif self.MatchAndSetMo(self.sectionDeclRe, oldAsm):\r
+ name = self.mo.group(1)\r
+ ty = self.mo.group(2)\r
+ if ty.lower() == 'section':\r
+ newAsm = '.' + name\r
+ else:\r
+ newAsm = ''\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+ elif self.MatchAndSetMo(self.procDeclRe, oldAsm):\r
+ proc = self.proc = self.mo.group(1)\r
+ visibility = self.mo.group(2)\r
+ if visibility is None:\r
+ visibility = ''\r
+ else:\r
+ visibility = visibility.lower()\r
+ if visibility != 'private':\r
+ self.NewGlobal(self.proc)\r
+ proc = 'ASM_PFX(' + proc + ')'\r
+ self.EmitNewContent('global ' + proc)\r
+ newAsm = proc + ':'\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+ uses = self.mo.group(3)\r
+ if uses is not None:\r
+ uses = filter(None, uses.split())\r
+ else:\r
+ uses = tuple()\r
+ self.uses = uses\r
+ for register in self.uses:\r
+ self.EmitNewContent(' push ' + register)\r
+ elif self.MatchAndSetMo(self.procEndRe, oldAsm):\r
+ newAsm = ''\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+ elif self.MatchAndSetMo(self.publicRe, oldAsm):\r
+ publics = re.findall(self.varAndTypeSubRe, self.mo.group(1))\r
+ publics = map(lambda p: p.split(':')[0].strip(), publics)\r
+ for i in range(len(publics) - 1):\r
+ name = publics[i]\r
+ self.EmitNewContent('global ASM_PFX(%s)' % publics[i])\r
+ self.NewGlobal(name)\r
+ name = publics[-1]\r
+ self.NewGlobal(name)\r
+ newAsm = 'global ASM_PFX(%s)' % name\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+ elif self.MatchAndSetMo(self.defineDataRe, oldAsm):\r
+ name = self.mo.group(1)\r
+ ty = self.mo.group(2)\r
+ value = self.mo.group(3)\r
+ if value == '?':\r
+ value = 0\r
+ newAsm = '%s: %s %s' % (name, ty, value)\r
+ newAsm = self.CommonConversions(newAsm)\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+ else:\r
+ newAsm = self.CommonConversions(oldAsm)\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+\r
+ def NewGlobal(self, name):\r
+ regex = re.compile(r'(?<![_\w\d])(?<!ASM_PFX\()(' + re.escape(name) +\r
+ r')(?![_\w\d])')\r
+ self.globals.add(regex)\r
+\r
+ def ConvertAnonymousLabels(self, oldAsm):\r
+ newAsm = oldAsm\r
+ anonLabel = self.anonLabel(self.anonLabelCount)\r
+ newAsm = newAsm.replace('@b', anonLabel)\r
+ newAsm = newAsm.replace('@B', anonLabel)\r
+ anonLabel = self.anonLabel(self.anonLabelCount + 1)\r
+ newAsm = newAsm.replace('@f', anonLabel)\r
+ newAsm = newAsm.replace('@F', anonLabel)\r
+ return newAsm\r
+\r
+ def anonLabel(self, count):\r
+ return '.%d' % count\r
+\r
+ def EmitString(self, string):\r
+ self.output.write(string)\r
+\r
+ def EmitLineWithDiff(self, old, new):\r
+ newLine = (self.indent + new).rstrip()\r
+ if self.diff:\r
+ if old is None:\r
+ print '+%s' % newLine\r
+ elif newLine != old:\r
+ print '-%s' % old\r
+ print '+%s' % newLine\r
+ else:\r
+ print '', newLine\r
+ if newLine != '':\r
+ self.newAsmEmptyLineCount = 0\r
+ self.EmitString(newLine + '\r\n')\r
+\r
+ def EmitLine(self, string):\r
+ self.EmitLineWithDiff(self.originalLine, string)\r
+\r
+ def EmitNewContent(self, string):\r
+ self.EmitLineWithDiff(None, string)\r
+\r
+ def EmitAsmReplaceOp(self, oldAsm, oldOp, newOp, endOfLine):\r
+ newAsm = oldAsm.replace(oldOp, newOp, 1)\r
+ self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
+\r
+ hexNumRe = re.compile(r'0*((?=[\da-f])\d*(?<=\d)[\da-f]*)h', re.IGNORECASE)\r
+\r
+ def EmitAsmWithComment(self, oldAsm, newAsm, endOfLine):\r
+ for glblRe in self.globals:\r
+ newAsm = glblRe.sub(r'ASM_PFX(\1)', newAsm)\r
+\r
+ newAsm = self.hexNumRe.sub(r'0x\1', newAsm)\r
+\r
+ newLine = newAsm + endOfLine\r
+ emitNewLine = ((newLine.strip() != '') or\r
+ ((oldAsm + endOfLine).strip() == ''))\r
+ if emitNewLine and newLine.strip() == '':\r
+ self.newAsmEmptyLineCount += 1\r
+ if self.newAsmEmptyLineCount > 1:\r
+ emitNewLine = False\r
+ if emitNewLine:\r
+ self.EmitLine(newLine.rstrip())\r
+ elif self.diff:\r
+ print '-%s' % self.originalLine\r
+\r
+ leaRe = re.compile(r'''\r
+ (lea \s+) ([\w@][\w@0-9]*) \s* , \s* (\S (?:.*\S)?)\r
+ \s* $\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ def ConvertLea(self, oldAsm):\r
+ newAsm = oldAsm\r
+ if self.MatchAndSetMo(self.leaRe, oldAsm):\r
+ lea = self.mo.group(1)\r
+ dst = self.mo.group(2)\r
+ src = self.mo.group(3)\r
+ if src.find('[') < 0:\r
+ src = '[' + src + ']'\r
+ newAsm = lea + dst + ', ' + src\r
+ newAsm = self.CommonConversions(newAsm)\r
+ return newAsm\r
+\r
+ ptrRe = re.compile(r'''\r
+ (?<! \S )\r
+ ([dfq]?word|byte) \s+ (?: ptr ) (\s*)\r
+ (?= [[\s] )\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ def ConvertPtr(self, oldAsm):\r
+ newAsm = oldAsm\r
+ while self.SearchAndSetMo(self.ptrRe, newAsm):\r
+ ty = self.mo.group(1)\r
+ if ty.lower() == 'fword':\r
+ ty = ''\r
+ else:\r
+ ty += self.mo.group(2)\r
+ newAsm = newAsm[:self.mo.start(0)] + ty + newAsm[self.mo.end(0):]\r
+ return newAsm\r
+\r
+ labelByteRe = re.compile(r'''\r
+ (?: \s+ label \s+ (?: [dfq]?word | byte ) )\r
+ (?! \S )\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ def ConvertLabelByte(self, oldAsm):\r
+ newAsm = oldAsm\r
+ if self.SearchAndSetMo(self.labelByteRe, newAsm):\r
+ newAsm = newAsm[:self.mo.start(0)] + ':' + newAsm[self.mo.end(0):]\r
+ return newAsm\r
+\r
+ unaryBitwiseOpRe = re.compile(r'''\r
+ ( NOT )\r
+ (?= \s+ \S )\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+ binaryBitwiseOpRe = re.compile(r'''\r
+ ( \S \s+ )\r
+ ( AND | OR | SHL | SHR )\r
+ (?= \s+ \S )\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+ bitwiseOpReplacements = {\r
+ 'not': '~',\r
+ 'and': '&',\r
+ 'shl': '<<',\r
+ 'shr': '>>',\r
+ 'or': '|',\r
+ }\r
+\r
+ def ConvertBitwiseOp(self, oldAsm):\r
+ newAsm = oldAsm\r
+ while self.SearchAndSetMo(self.binaryBitwiseOpRe, newAsm):\r
+ prefix = self.mo.group(1)\r
+ op = self.bitwiseOpReplacements[self.mo.group(2).lower()]\r
+ newAsm = newAsm[:self.mo.start(0)] + prefix + op + \\r
+ newAsm[self.mo.end(0):]\r
+ while self.SearchAndSetMo(self.unaryBitwiseOpRe, newAsm):\r
+ op = self.bitwiseOpReplacements[self.mo.group(1).lower()]\r
+ newAsm = newAsm[:self.mo.start(0)] + op + newAsm[self.mo.end(0):]\r
+ return newAsm\r
+\r
+ sectionRe = re.compile(r'''\r
+ \. ( code |\r
+ data\r
+ )\r
+ (?: \s+ .* )?\r
+ \s* $\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ segmentRe = re.compile(r'''\r
+ ( code |\r
+ data )\r
+ (?: \s+ SEGMENT )\r
+ (?: \s+ .* )?\r
+ \s* $\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ def ConvertSection(self, oldAsm):\r
+ newAsm = oldAsm\r
+ if self.MatchAndSetMo(self.sectionRe, newAsm) or \\r
+ self.MatchAndSetMo(self.segmentRe, newAsm):\r
+ name = self.mo.group(1).lower()\r
+ if name == 'code':\r
+ if self.x64:\r
+ self.EmitLine('DEFAULT REL')\r
+ name = 'text'\r
+ newAsm = 'SECTION .' + name\r
+ return newAsm\r
+\r
+ fwordRe = re.compile(r'''\r
+ (?<! \S )\r
+ fword\r
+ (?! \S )\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ def FwordUnsupportedCheck(self, oldAsm):\r
+ newAsm = oldAsm\r
+ if self.SearchAndSetMo(self.fwordRe, newAsm):\r
+ newAsm = self.Unsupported(newAsm, 'fword used')\r
+ return newAsm\r
+\r
+ __common_conversion_routines__ = (\r
+ ConvertAnonymousLabels,\r
+ ConvertPtr,\r
+ FwordUnsupportedCheck,\r
+ ConvertBitwiseOp,\r
+ ConvertLabelByte,\r
+ ConvertSection,\r
+ )\r
+\r
+ def CommonConversions(self, oldAsm):\r
+ newAsm = oldAsm\r
+ for conv in self.__common_conversion_routines__:\r
+ newAsm = conv(self, newAsm)\r
+ return newAsm\r
+\r
+ def Unsupported(self, asm, message=None):\r
+ if not self.force:\r
+ raise UnsupportedConversion\r
+\r
+ self.unsupportedSyntaxSeen = True\r
+ newAsm = '%error conversion unsupported'\r
+ if message:\r
+ newAsm += '; ' + message\r
+ newAsm += ': ' + asm\r
+ return newAsm\r
+\r
+\r
+class ConvertInfFile(CommonUtils):\r
+\r
+ def __init__(self, inf, clone):\r
+ CommonUtils.__init__(self, clone)\r
+ self.inf = inf\r
+ self.ScanInfAsmFiles()\r
+ if self.infmode:\r
+ self.ConvertInfAsmFiles()\r
+\r
+ infSrcRe = re.compile(r'''\r
+ \s*\r
+ ( [\w@][\w@0-9/]* \.(asm|s) )\r
+ \s* (?: \| [^#]* )?\r
+ \s* (?: \# .* )?\r
+ $\r
+ ''',\r
+ re.VERBOSE | re.IGNORECASE\r
+ )\r
+\r
+ def GetInfAsmFileMapping(self):\r
+ srcToDst = {'order': []}\r
+ for line in self.lines:\r
+ line = line.rstrip()\r
+ if self.MatchAndSetMo(self.infSrcRe, line):\r
+ src = self.mo.group(1)\r
+ srcExt = self.mo.group(2)\r
+ dst = os.path.splitext(src)[0] + '.nasm'\r
+ if src not in srcToDst:\r
+ srcToDst[src] = dst\r
+ srcToDst['order'].append(src)\r
+ return srcToDst\r
+\r
+ def ScanInfAsmFiles(self):\r
+ src = self.inf\r
+ assert os.path.isfile(src)\r
+ f = open(src)\r
+ self.lines = f.readlines()\r
+ f.close()\r
+\r
+ path = os.path.realpath(self.inf)\r
+ (self.dir, inf) = os.path.split(path)\r
+ parent = os.path.normpath(self.dir)\r
+ (lastpath, self.moduleName) = os.path.split(parent)\r
+ self.packageName = None\r
+ while True:\r
+ lastpath = os.path.normpath(lastpath)\r
+ (parent, basename) = os.path.split(lastpath)\r
+ if parent == lastpath:\r
+ break\r
+ if basename.endswith('Pkg'):\r
+ self.packageName = basename\r
+ break\r
+ lastpath = parent\r
+\r
+ self.srcToDst = self.GetInfAsmFileMapping()\r
+\r
+ self.dstToSrc = {'order': []}\r
+ for src in self.srcToDst['order']:\r
+ srcExt = os.path.splitext(src)[1]\r
+ dst = self.srcToDst[src]\r
+ if dst not in self.dstToSrc:\r
+ self.dstToSrc[dst] = [src]\r
+ self.dstToSrc['order'].append(dst)\r
+ else:\r
+ self.dstToSrc[dst].append(src)\r
+\r
+ def __len__(self):\r
+ return len(self.dstToSrc['order'])\r
+\r
+ def __iter__(self):\r
+ return iter(self.dstToSrc['order'])\r
+\r
+ def ConvertInfAsmFiles(self):\r
+ notConverted = []\r
+ unsupportedArchCount = 0\r
+ for dst in self:\r
+ didSomething = False\r
+ fileChanged = self.UpdateInfAsmFile(dst)\r
+ try:\r
+ self.UpdateInfAsmFile(dst)\r
+ didSomething = True\r
+ except UnsupportedConversion:\r
+ if not self.Opt.quiet:\r
+ print 'MASM=>NASM conversion unsupported for', dst\r
+ notConverted.append(dst)\r
+ except NoSourceFile:\r
+ if not self.Opt.quiet:\r
+ print 'Source file missing for', reldst\r
+ notConverted.append(dst)\r
+ except UnsupportedArch:\r
+ unsupportedArchCount += 1\r
+ else:\r
+ if didSomething:\r
+ self.ConversionFinished(dst)\r
+ if len(notConverted) > 0 and not self.Opt.quiet:\r
+ for dst in notConverted:\r
+ reldst = self.RootRelative(dst)\r
+ print 'Unabled to convert', reldst\r
+ if unsupportedArchCount > 0 and not self.Opt.quiet:\r
+ print 'Skipped', unsupportedArchCount, 'files based on architecture'\r
+\r
+ def UpdateInfAsmFile(self, dst, IgnoreMissingAsm=False):\r
+ infPath = os.path.split(os.path.realpath(self.inf))[0]\r
+ asmSrc = os.path.splitext(dst)[0] + '.asm'\r
+ fullSrc = os.path.join(infPath, asmSrc)\r
+ fullDst = os.path.join(infPath, dst)\r
+ srcParentDir = os.path.basename(os.path.split(fullSrc)[0])\r
+ if srcParentDir.lower() in UnsupportedArch.unsupported:\r
+ raise UnsupportedArch\r
+ elif not os.path.exists(fullSrc):\r
+ if not IgnoreMissingAsm:\r
+ raise NoSourceFile\r
+ else: # not os.path.exists(fullDst):\r
+ conv = ConvertAsmFile(fullSrc, fullDst, self)\r
+ self.unsupportedSyntaxSeen = conv.unsupportedSyntaxSeen\r
+\r
+ lastLine = ''\r
+ fileChanged = False\r
+ for i in range(len(self.lines)):\r
+ line = self.lines[i].rstrip()\r
+ updatedLine = line\r
+ for src in self.dstToSrc[dst]:\r
+ assert self.srcToDst[src] == dst\r
+ updatedLine = self.ReplacePreserveSpacing(\r
+ updatedLine, src, dst)\r
+\r
+ lineChanged = updatedLine != line\r
+ if lineChanged:\r
+ if lastLine.strip() == updatedLine.strip():\r
+ self.lines[i] = None\r
+ else:\r
+ self.lines[i] = updatedLine + '\r\n'\r
+\r
+ if self.diff:\r
+ if lineChanged:\r
+ print '-%s' % line\r
+ if self.lines[i] is not None:\r
+ print '+%s' % updatedLine\r
+ else:\r
+ print '', line\r
+\r
+ fileChanged |= lineChanged\r
+ if self.lines[i] is not None:\r
+ lastLine = self.lines[i]\r
+\r
+ if fileChanged:\r
+ self.lines = filter(lambda l: l is not None, self.lines)\r
+\r
+ for src in self.dstToSrc[dst]:\r
+ if not src.endswith('.asm'):\r
+ fullSrc = os.path.join(infPath, src)\r
+ if os.path.exists(fullSrc):\r
+ self.RemoveFile(fullSrc)\r
+\r
+ if fileChanged:\r
+ f = open(self.inf, 'wb')\r
+ f.writelines(self.lines)\r
+ f.close()\r
+ self.FileUpdated(self.inf)\r
+\r
+ def ConversionFinished(self, dst):\r
+ asmSrc = os.path.splitext(dst)[0] + '.asm'\r
+ self.FileConversionFinished(\r
+ self.packageName, self.moduleName, asmSrc, dst)\r
+\r
+\r
+class ConvertInfFiles(CommonUtils):\r
+\r
+ def __init__(self, infs, clone):\r
+ CommonUtils.__init__(self, clone)\r
+ infs = map(lambda i: ConvertInfFile(i, self), infs)\r
+ infs = filter(lambda i: len(i) > 0, infs)\r
+ dstToInfs = {'order': []}\r
+ for inf in infs:\r
+ for dst in inf:\r
+ fulldst = os.path.realpath(os.path.join(inf.dir, dst))\r
+ pair = (inf, dst)\r
+ if fulldst in dstToInfs:\r
+ dstToInfs[fulldst].append(pair)\r
+ else:\r
+ dstToInfs['order'].append(fulldst)\r
+ dstToInfs[fulldst] = [pair]\r
+\r
+ notConverted = []\r
+ unsupportedArchCount = 0\r
+ for dst in dstToInfs['order']:\r
+ didSomething = False\r
+ try:\r
+ for inf, reldst in dstToInfs[dst]:\r
+ inf.UpdateInfAsmFile(reldst, IgnoreMissingAsm=didSomething)\r
+ didSomething = True\r
+ except UnsupportedConversion:\r
+ if not self.Opt.quiet:\r
+ print 'MASM=>NASM conversion unsupported for', reldst\r
+ notConverted.append(dst)\r
+ except NoSourceFile:\r
+ if not self.Opt.quiet:\r
+ print 'Source file missing for', reldst\r
+ notConverted.append(dst)\r
+ except UnsupportedArch:\r
+ unsupportedArchCount += 1\r
+ else:\r
+ if didSomething:\r
+ inf.ConversionFinished(reldst)\r
+ if len(notConverted) > 0 and not self.Opt.quiet:\r
+ for dst in notConverted:\r
+ reldst = self.RootRelative(dst)\r
+ print 'Unabled to convert', reldst\r
+ if unsupportedArchCount > 0 and not self.Opt.quiet:\r
+ print 'Skipped', unsupportedArchCount, 'files based on architecture'\r
+\r
+\r
+class ConvertDirectories(CommonUtils):\r
+\r
+ def __init__(self, paths, clone):\r
+ CommonUtils.__init__(self, clone)\r
+ self.paths = paths\r
+ self.ConvertInfAndAsmFiles()\r
+\r
+ def ConvertInfAndAsmFiles(self):\r
+ infs = list()\r
+ for path in self.paths:\r
+ assert(os.path.exists(path))\r
+ for path in self.paths:\r
+ for root, dirs, files in os.walk(path):\r
+ for d in ('.svn', '.git'):\r
+ if d in dirs:\r
+ dirs.remove(d)\r
+ for f in files:\r
+ if f.lower().endswith('.inf'):\r
+ inf = os.path.realpath(os.path.join(root, f))\r
+ infs.append(inf)\r
+\r
+ ConvertInfFiles(infs, self)\r
+\r
+\r
+class ConvertAsmApp(CommonUtils):\r
+\r
+ def __init__(self):\r
+ CommonUtils.__init__(self)\r
+\r
+ numArgs = len(self.Args)\r
+ assert(numArgs >= 1)\r
+ if self.infmode:\r
+ ConvertInfFiles(self.Args, self)\r
+ elif self.dirmode:\r
+ ConvertDirectories(self.Args, self)\r
+ elif not self.dirmode:\r
+ assert(numArgs <= 2)\r
+ src = self.Args[0]\r
+ if numArgs > 1:\r
+ dst = self.Args[1]\r
+ else:\r
+ dst = None\r
+ ConvertAsmFile(src, dst, self)\r
+\r
+ConvertAsmApp()\r