4 strip_asm.py - Cleanup ASM output for the specified file
7 from argparse
import ArgumentParser
13 def find_used_labels(asm
):
15 label_re
= re
.compile("\s*j[a-z]+\s+\.L([a-zA-Z0-9][a-zA-Z0-9_]*)")
16 for l
in asm
.splitlines():
19 found
.add(".L%s" % m
.group(1))
23 def normalize_labels(asm
):
25 label_decl
= re
.compile("^[.]{0,1}L([a-zA-Z0-9][a-zA-Z0-9_]*)(?=:)")
26 for l
in asm
.splitlines():
27 m
= label_decl
.match(l
)
32 needs_dot
= next(iter(decls
))[0] != "."
36 asm
= re
.sub("(^|\s+)" + ld
+ "(?=:|\s)", "\\1." + ld
, asm
)
40 def transform_labels(asm
):
41 asm
= normalize_labels(asm
)
42 used_decls
= find_used_labels(asm
)
44 label_decl
= re
.compile("^\.L([a-zA-Z0-9][a-zA-Z0-9_]*)(?=:)")
45 for l
in asm
.splitlines():
46 m
= label_decl
.match(l
)
47 if not m
or m
.group(0) in used_decls
:
53 def is_identifier(tk
):
57 if not first
.isalpha() and first
!= "_":
59 for i
in range(1, len(tk
)):
61 if not c
.isalnum() and c
!= "_":
66 def process_identifiers(l
):
68 process_identifiers - process all identifiers and modify them to have
69 consistent names across all platforms; specifically across ELF and MachO.
70 For example, MachO inserts an additional understore at the beginning of
71 names. This function removes that.
73 parts
= re
.split(r
"([a-zA-Z0-9_]+)", l
)
77 if tk
.startswith("__Z"):
80 tk
.startswith("_") and len(tk
) > 1 and tk
[1].isalpha() and tk
[1] != "Z"
89 Strip the ASM of unwanted directives and lines
92 asm
= transform_labels(asm
)
94 # TODO: Add more things we want to remove
96 re
.compile("\s+\..*$"), # directive
97 re
.compile("\s*#(NO_APP|APP)$"), # inline ASM
98 re
.compile("\s*#.*$"), # comment line
99 re
.compile("\s*\.globa?l\s*([.a-zA-Z_][a-zA-Z0-9$_.]*)"), # global directive
101 "\s*\.(string|asciz|ascii|[1248]?byte|short|word|long|quad|value|zero)"
105 fn_label_def
= re
.compile("^[a-zA-Z_][a-zA-Z0-9_.]*:")
106 for l
in asm
.splitlines():
107 # Remove Mach-O attribute
108 l
= l
.replace("@GOTPCREL", "")
110 for reg
in discard_regexes
:
111 if reg
.match(l
) is not None:
114 for reg
in keep_regexes
:
115 if reg
.match(l
) is not None:
119 if fn_label_def
.match(l
) and len(new_contents
) != 0:
121 l
= process_identifiers(l
)
128 parser
= ArgumentParser(description
="generate a stripped assembly file")
130 "input", metavar
="input", type=str, nargs
=1, help="An input assembly file"
133 "out", metavar
="output", type=str, nargs
=1, help="The output file"
135 args
, unknown_args
= parser
.parse_known_args()
136 input = args
.input[0]
138 if not os
.path
.isfile(input):
139 print(("ERROR: input file '%s' does not exist") % input)
142 with
open(input, "r") as f
:
144 new_contents
= process_asm(contents
)
145 with
open(output
, "w") as f
:
146 f
.write(new_contents
)
149 if __name__
== "__main__":
152 # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
153 # kate: tab-width: 4; replace-tabs on; indent-width 4; tab-indents: off;
154 # kate: indent-mode python; remove-trailing-spaces modified;