4 strip_asm.py - Cleanup ASM output for the specified file
7 from argparse
import ArgumentParser
12 def find_used_labels(asm
):
14 label_re
= re
.compile("\s*j[a-z]+\s+\.L([a-zA-Z0-9][a-zA-Z0-9_]*)")
15 for l
in asm
.splitlines():
18 found
.add('.L%s' % m
.group(1))
22 def normalize_labels(asm
):
24 label_decl
= re
.compile("^[.]{0,1}L([a-zA-Z0-9][a-zA-Z0-9_]*)(?=:)")
25 for l
in asm
.splitlines():
26 m
= label_decl
.match(l
)
31 needs_dot
= next(iter(decls
))[0] != '.'
35 asm
= re
.sub("(^|\s+)" + ld
+ "(?=:|\s)", '\\1.' + ld
, asm
)
39 def transform_labels(asm
):
40 asm
= normalize_labels(asm
)
41 used_decls
= find_used_labels(asm
)
43 label_decl
= re
.compile("^\.L([a-zA-Z0-9][a-zA-Z0-9_]*)(?=:)")
44 for l
in asm
.splitlines():
45 m
= label_decl
.match(l
)
46 if not m
or m
.group(0) in used_decls
:
52 def is_identifier(tk
):
56 if not first
.isalpha() and first
!= '_':
58 for i
in range(1, len(tk
)):
60 if not c
.isalnum() and c
!= '_':
64 def process_identifiers(l
):
66 process_identifiers - process all identifiers and modify them to have
67 consistent names across all platforms; specifically across ELF and MachO.
68 For example, MachO inserts an additional understore at the beginning of
69 names. This function removes that.
71 parts
= re
.split(r
'([a-zA-Z0-9_]+)', l
)
75 if tk
.startswith('__Z'):
77 elif tk
.startswith('_') and len(tk
) > 1 and \
78 tk
[1].isalpha() and tk
[1] != 'Z':
86 Strip the ASM of unwanted directives and lines
89 asm
= transform_labels(asm
)
91 # TODO: Add more things we want to remove
93 re
.compile("\s+\..*$"), # directive
94 re
.compile("\s*#(NO_APP|APP)$"), #inline ASM
95 re
.compile("\s*#.*$"), # comment line
96 re
.compile("\s*\.globa?l\s*([.a-zA-Z_][a-zA-Z0-9$_.]*)"), #global directive
97 re
.compile("\s*\.(string|asciz|ascii|[1248]?byte|short|word|long|quad|value|zero)"),
102 fn_label_def
= re
.compile("^[a-zA-Z_][a-zA-Z0-9_.]*:")
103 for l
in asm
.splitlines():
104 # Remove Mach-O attribute
105 l
= l
.replace('@GOTPCREL', '')
107 for reg
in discard_regexes
:
108 if reg
.match(l
) is not None:
111 for reg
in keep_regexes
:
112 if reg
.match(l
) is not None:
116 if fn_label_def
.match(l
) and len(new_contents
) != 0:
118 l
= process_identifiers(l
)
124 parser
= ArgumentParser(
125 description
='generate a stripped assembly file')
127 'input', metavar
='input', type=str, nargs
=1,
128 help='An input assembly file')
130 'out', metavar
='output', type=str, nargs
=1,
131 help='The output file')
132 args
, unknown_args
= parser
.parse_known_args()
133 input = args
.input[0]
135 if not os
.path
.isfile(input):
136 print(("ERROR: input file '%s' does not exist") % input)
139 with
open(input, 'r') as f
:
141 new_contents
= process_asm(contents
)
142 with
open(output
, 'w') as f
:
143 f
.write(new_contents
)
146 if __name__
== '__main__':
149 # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
150 # kate: tab-width: 4; replace-tabs on; indent-width 4; tab-indents: off;
151 # kate: indent-mode python; remove-trailing-spaces modified;