xasm 1.2.1__py312-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
xasm/pyc_convert.py ADDED
@@ -0,0 +1,259 @@
1
+ #!/usr/bin/env python
2
+ """Convert Python Bytecode from one version to another for
3
+ some limited set of Python bytecode versions
4
+ """
5
+ import os
6
+ import os.path as osp
7
+ from copy import copy
8
+ from tempfile import NamedTemporaryFile
9
+
10
+ import click
11
+ import xdis
12
+ from xdis import disassemble_file, load_module, magic2int, write_bytecode_file
13
+ from xdis.magics import magics
14
+ from xdis.opcodes import opcode_27, opcode_33
15
+
16
+ from xasm.assemble import (
17
+ Assembler,
18
+ Instruction,
19
+ asm_file,
20
+ create_code,
21
+ decode_lineno_tab_old,
22
+ )
23
+ from xasm.version import __version__
24
+ from xasm.write_pyc import write_pycfile
25
+
26
+
27
+ def add_credit(asm, src_version, dest_version) -> None:
28
+ stamp = "Converted from Python %s to %s by %s version %s" % (
29
+ src_version,
30
+ dest_version,
31
+ "pyc-convert",
32
+ __version__,
33
+ )
34
+ asm.codes[-1].co_consts = list(asm.codes[-1].co_consts).append(stamp)
35
+ return
36
+
37
+
38
+ def copy_magic_into_pyc(input_pyc, output_pyc, src_version, dest_version) -> None:
39
+ """Bytecodes are the same except the magic number, so just change
40
+ that"""
41
+ (version, timestamp, magic_int, co, is_pypy, source_size) = load_module(input_pyc)
42
+ assert version == float(
43
+ src_version
44
+ ), f"Need Python {src_version} bytecode; got bytecode for version {version}"
45
+ magic_int = magic2int(magics.magics[dest_version])
46
+ write_bytecode_file(output_pyc, co, magic_int)
47
+ print(f"Wrote {output_pyc}")
48
+ return
49
+
50
+
51
+ def xlate26_27(inst) -> None:
52
+ """Between 2.6 and 2.7 opcode values changed
53
+ Adjust for the differences by using the opcode name
54
+ """
55
+ inst.opcode = opcode_27.opmap[inst.opname]
56
+
57
+
58
+ def conversion_to_version(conversion_type, is_dest=False):
59
+ if is_dest:
60
+ return conversion_type[-2] + "." + conversion_type[-1]
61
+ else:
62
+ return conversion_type[0] + "." + conversion_type[1]
63
+
64
+
65
+ def transform_26_27(inst, new_inst, i, n, offset, instructions, new_asm):
66
+ """Change JUMP_IF_FALSE and JUMP_IF_TRUE to
67
+ POP_JUMP_IF_FALSE and POP_JUMP_IF_TRUE"""
68
+ if inst.opname in ("JUMP_IF_FALSE", "JUMP_IF_TRUE"):
69
+ i += 1
70
+ assert i < n
71
+ assert instructions[i].opname == "POP_TOP"
72
+ new_inst.offset = offset
73
+ new_inst.opname = (
74
+ "POP_JUMP_IF_FALSE"
75
+ if inst.opname == "JUMP_IF_FALSE"
76
+ else "POP_JUMP_IF_TRUE"
77
+ )
78
+ new_asm.backpatch[-1].remove(inst)
79
+ new_inst.arg = "L%d" % (inst.offset + inst.arg + 3)
80
+ new_asm.backpatch[-1].add(new_inst)
81
+ else:
82
+ xlate26_27(new_inst)
83
+ return xdis.op_size(new_inst.opcode, opcode_27)
84
+
85
+
86
+ def transform_32_33(inst, new_inst, i, n, offset, instructions, new_asm):
87
+ """MAKE_FUNCTION adds another const. probably MAKE_CLASS as well"""
88
+ add_size = xdis.op_size(new_inst.opcode, opcode_33)
89
+ if inst.opname in ("MAKE_FUNCTION", "MAKE_CLOSURE"):
90
+ # Previous instruction should be a load const which
91
+ # contains the name of the function to call
92
+ prev_inst = instructions[i - 1]
93
+ assert prev_inst.opname == "LOAD_CONST"
94
+ assert isinstance(prev_inst.arg, int)
95
+
96
+ # Add the function name as an additional LOAD_CONST
97
+ load_fn_const = Instruction()
98
+ load_fn_const.opname = "LOAD_CONST"
99
+ load_fn_const.opcode = opcode_33.opmap["LOAD_CONST"]
100
+ load_fn_const.line_no = None
101
+ prev_const = new_asm.code.co_consts[prev_inst.arg]
102
+ if hasattr(prev_const, "co_name"):
103
+ fn_name = new_asm.code.co_consts[prev_inst.arg].co_name
104
+ else:
105
+ fn_name = "what-is-up"
106
+ const_index = len(new_asm.code.co_consts)
107
+ new_asm.code.co_consts = list(new_asm.code.co_consts)
108
+ new_asm.code.co_consts.append(fn_name)
109
+ load_fn_const.arg = const_index
110
+ load_fn_const.offset = offset
111
+ load_fn_const.starts_line = False
112
+ load_fn_const.is_jump_target = False
113
+ new_asm.code.instructions.append(load_fn_const)
114
+ load_const_size = xdis.op_size(load_fn_const.opcode, opcode_33)
115
+ add_size += load_const_size
116
+ new_inst.offset = offset + add_size
117
+ pass
118
+ return add_size
119
+
120
+
121
+ def transform_33_32(inst, new_inst, i, n, offset, instructions, new_asm):
122
+ """MAKE_FUNCTION, and MAKE_CLOSURE have an additional LOAD_CONST of a name
123
+ that are not in Python 3.2. Remove these.
124
+ """
125
+ add_size = xdis.op_size(new_inst.opcode, opcode_33)
126
+ if inst.opname in ("MAKE_FUNCTION", "MAKE_CLOSURE"):
127
+ # Previous instruction should be a load const which
128
+ # contains the name of the function to call
129
+ prev_inst = instructions[i - 1]
130
+ assert prev_inst.opname == "LOAD_CONST"
131
+ assert isinstance(prev_inst.arg, int)
132
+ assert len(instructions) > 2
133
+ assert len(instructions) > 2
134
+ prev_inst2 = instructions[i - 2]
135
+ assert prev_inst2.opname == "LOAD_CONST"
136
+ assert isinstance(prev_inst2.arg, int)
137
+
138
+ # Remove the function name as an additional LOAD_CONST
139
+ prev2_const = new_asm.code.co_consts[prev_inst.arg]
140
+ assert hasattr(prev2_const, "co_name")
141
+ new_asm.code.instructions = new_asm.code.instructions[:-1]
142
+ load_const_size = xdis.op_size(prev_inst.opcode, opcode_33)
143
+ add_size -= load_const_size
144
+ new_inst.offset = offset - add_size
145
+ return -load_const_size
146
+ return 0
147
+
148
+
149
+ def transform_asm(
150
+ asm: Assembler | None, conversion_type, src_version, dest_version
151
+ ) -> Assembler:
152
+ new_asm = Assembler(dest_version, is_pypy=False)
153
+ for field in "code size".split():
154
+ setattr(new_asm, field, copy(getattr(asm, field)))
155
+
156
+ if conversion_type == "26-27":
157
+ transform_fn = transform_26_27
158
+ elif conversion_type == "32-33":
159
+ transform_fn = transform_32_33
160
+ elif conversion_type == "33-32":
161
+ transform_fn = transform_33_32
162
+ else:
163
+ raise RuntimeError(f"Don't know how to convert {conversion_type} ")
164
+ for j, code in enumerate(asm.code_list):
165
+ offset2label = {v: k for k, v in asm.label[j].items()}
166
+ new_asm.backpatch.append(copy(asm.backpatch[j]))
167
+ new_asm.label.append(copy(asm.label[j]))
168
+ new_asm.codes.append(copy(code))
169
+ new_asm.code.co_lnotab = decode_lineno_tab_old(
170
+ code.co_lnotab, code.co_firstlineno
171
+ )
172
+ instructions = asm.codes[j].instructions
173
+ new_asm.code.instructions = []
174
+ i, offset, n = 0, 0, len(instructions)
175
+ while i < n:
176
+ inst = instructions[i]
177
+ new_inst = copy(inst)
178
+ inst_size = transform_fn(
179
+ inst, new_inst, i, offset, n, instructions, new_asm
180
+ )
181
+ if inst.offset in offset2label:
182
+ new_asm.label[-1][offset2label[inst.offset]] = offset
183
+ pass
184
+ offset += inst_size
185
+ new_asm.code.instructions.append(new_inst)
186
+ i += 1
187
+ pass
188
+
189
+ co, is_valid = create_code(new_asm, new_asm.label[-1], new_asm.backpatch[-1])
190
+ new_asm.code_list.append(co)
191
+ new_asm.code_list.reverse()
192
+ new_asm.status = "finished" if is_valid else "invalid"
193
+ return new_asm
194
+
195
+
196
+ UPWARD_COMPATIBLE = tuple("20-21 21-22 23-24 24-23".split())
197
+
198
+
199
+ @click.command()
200
+ @click.option(
201
+ "--conversion-type",
202
+ "-t",
203
+ type=click.Choice(
204
+ [
205
+ "20-21",
206
+ "21-22",
207
+ "23-24",
208
+ "24-23",
209
+ "24-25",
210
+ "25-26",
211
+ "26-27",
212
+ "32-33",
213
+ "33-32",
214
+ ]
215
+ ),
216
+ help="specify conversion from/to bytecode",
217
+ default="26-27",
218
+ )
219
+ @click.argument("input_pyc", type=click.Path(writable=True), nargs=1)
220
+ @click.argument(
221
+ "output_pyc", type=click.Path(writable=True), required=False, nargs=1, default=None
222
+ )
223
+ def main(conversion_type, input_pyc, output_pyc) -> None:
224
+ """Convert Python bytecode from one version to another.
225
+
226
+ INPUT_PYC contains the input bytecode path name
227
+ OUTPUT_PYC contains the output bytecode path name if supplied
228
+ The --conversion type option specifies what conversion to do.
229
+
230
+ Note: there are a very limited set of conversions currently supported.
231
+ Help out and write more!"""
232
+
233
+ shortname = osp.basename(input_pyc)
234
+ if shortname.endswith(".pyc"):
235
+ shortname = shortname[:-4]
236
+ src_version = conversion_to_version(conversion_type, is_dest=False)
237
+ dest_version = conversion_to_version(conversion_type, is_dest=True)
238
+ if output_pyc is None:
239
+ output_pyc = f"{shortname}-{dest_version}.pyc"
240
+
241
+ if conversion_type in UPWARD_COMPATIBLE:
242
+ copy_magic_into_pyc(input_pyc, output_pyc, src_version, dest_version)
243
+ return
244
+ temp_asm = NamedTemporaryFile("w", suffix=".pyasm", prefix=shortname, delete=False)
245
+ (filename, co, version, timestamp, magic_int) = disassemble_file(
246
+ input_pyc, temp_asm, asm_format=True
247
+ )
248
+ temp_asm.close()
249
+ assert version == float(
250
+ src_version
251
+ ), f"Need Python {src_version} bytecode; got bytecode for version {version}"
252
+ asm = asm_file(temp_asm.name)
253
+ new_asm = transform_asm(asm, conversion_type, src_version, dest_version)
254
+ os.unlink(temp_asm.name)
255
+ write_pycfile(output_pyc, new_asm)
256
+
257
+
258
+ if __name__ == "__main__":
259
+ main()
xasm/version.py ADDED
@@ -0,0 +1,8 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # This file is suitable for sourcing inside POSIX shell as
4
+ # well as importing into Python. That's why there is no
5
+ # space around "=" below.
6
+
7
+ # fmt: off
8
+ __version__="1.2.1" # noqa
xasm/write_pyc.py ADDED
@@ -0,0 +1,48 @@
1
+ import time
2
+ from struct import pack
3
+
4
+ import xdis
5
+ from xdis import magic2int
6
+ from xdis.magics import magics
7
+ from xdis.marsh import dumps
8
+ from xdis.version_info import PYTHON3, version_tuple_to_str
9
+
10
+
11
+ def write_pycfile(fp, code_list, timestamp=None, version_triple=xdis.PYTHON_VERSION_TRIPLE) -> int:
12
+
13
+ rc = 0
14
+ version_str = version_tuple_to_str(version_triple, end=2)
15
+ magic_bytes = magics[version_str]
16
+ magic_int = magic2int(magic_bytes)
17
+ fp.write(magic_bytes)
18
+
19
+ if timestamp is None:
20
+ timestamp = int(time.time())
21
+ write_source_size = version_triple >= (3, 3)
22
+ if version_triple >= (3, 7):
23
+ if magic_int == 3393:
24
+ fp.write(pack("I", timestamp))
25
+ fp.write(pack("I", 0))
26
+ else:
27
+ # PEP 552. https://www.python.org/dev/peps/pep-0552/
28
+ # 0 in the lowest-order bit means used old-style timestamps
29
+ fp.write(pack("<I", 0))
30
+ fp.write(pack("<I", timestamp))
31
+ else:
32
+ fp.write(pack("<I", timestamp))
33
+
34
+ if write_source_size:
35
+ fp.write(pack("<I", 0)) # size mod 2**32
36
+
37
+ for co in code_list:
38
+ try:
39
+ co_obj = dumps(co, python_version=version_triple)
40
+ if PYTHON3 and version_triple < (3, 0):
41
+ co_obj = str.encode(co_obj)
42
+ pass
43
+
44
+ fp.write(co_obj)
45
+ except Exception as e:
46
+ print(f"error dumping {co}: {e}; ignoring")
47
+ rc = 1
48
+ return rc
xasm/xasm_cli.py ADDED
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env python
2
+ import os
3
+ import sys
4
+ from typing import List
5
+
6
+ import click
7
+ import xdis
8
+ from xdis.version_info import version_tuple_to_str
9
+
10
+ from xasm.assemble import asm_file
11
+ from xasm.write_pyc import write_pycfile
12
+
13
+
14
+ @click.command()
15
+ @click.option("--pyc-file", default=None)
16
+ @click.argument("asm-path", type=click.Path(exists=True, readable=True), required=True)
17
+ def main(pyc_file: List[str], asm_path):
18
+ """
19
+ Create Python bytecode from a Python assembly file.
20
+
21
+ ASM_PATH gives the input Python assembly file. We suggest ending the
22
+ file in .pyc
23
+
24
+ If --pyc-file is given, that indicates the path to write the
25
+ Python bytecode. The path should end in '.pyc'.
26
+
27
+ See https://github.com/rocky/python-xasm/blob/master/HOW-TO-USE.rst
28
+ for how to write a Python assembler file.
29
+ """
30
+ if os.stat(asm_path).st_size == 0:
31
+ print(f"Size of assembly file {asm_path} is zero")
32
+ sys.exit(1)
33
+ asm = asm_file(asm_path)
34
+
35
+ if not pyc_file:
36
+ if asm_path.endswith(".pyasm"):
37
+ pyc_file = asm_path[: -len(".pyasm")] + ".pyc"
38
+ elif not pyc_file and asm_path.endswith(".xasm"):
39
+ pyc_file = asm_path[: -len(".xasm")] + ".pyc"
40
+
41
+ if xdis.PYTHON3:
42
+ file_mode = "wb"
43
+ else:
44
+ file_mode = "w"
45
+
46
+ with open(pyc_file, file_mode) as fp:
47
+ rc = write_pycfile(fp, asm.code_list, asm.timestamp, asm.python_version)
48
+ size = fp.tell()
49
+ print(
50
+ f"""Wrote Python {version_tuple_to_str(asm.python_version)} bytecode file "{pyc_file}"; {size} bytes."""
51
+ )
52
+ if size <= 16:
53
+ print("Warning: bytecode file is too small to be usable.")
54
+ rc = 2
55
+ if rc != 0:
56
+ print(f"Exiting with return code {rc}")
57
+ sys.exit(rc)
58
+
59
+
60
+ if __name__ == "__main__":
61
+ main(sys.argv[1:])
@@ -0,0 +1,233 @@
1
+ Metadata-Version: 2.4
2
+ Name: xasm
3
+ Version: 1.2.1
4
+ Summary: Cross-version Python bytecode assembler
5
+ Author-email: Rocky Bernstein <rb@dustyfeet.com>
6
+ License-Expression: GPL-2.0
7
+ Project-URL: Homepage, https://github.com/rocky/python-xasm
8
+ Project-URL: Downloads, https://github.com/rocky/python-xasm/releases
9
+ Keywords: Python bytecode,bytecode,disassembler
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python
13
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Code Generators
21
+ Description-Content-Type: text/x-rst
22
+ License-File: LICENSE.gpl2
23
+ Requires-Dist: click
24
+ Requires-Dist: xdis<6.3.0,>=6.1.1
25
+ Provides-Extra: dev
26
+ Requires-Dist: pre-commit; extra == "dev"
27
+ Requires-Dist: black; extra == "dev"
28
+ Requires-Dist: isort; extra == "dev"
29
+ Requires-Dist: pytest; extra == "dev"
30
+ Dynamic: license-file
31
+
32
+ |Pypi Installs| |Latest Version| |Supported Python Versions|
33
+
34
+ xasm
35
+ ====
36
+
37
+ *NOTE: this is in beta.*
38
+
39
+ A cross-version Python bytecode assembler
40
+
41
+
42
+ Introduction
43
+ ------------
44
+
45
+ The Python ``xasm`` module has routines for assembly, and has a command to
46
+ assemble bytecode for several different versions of Python.
47
+
48
+ Here are some potential uses:
49
+
50
+ * Make small changes to existing Python bytecode when you don’t have source
51
+ * Craft custom and efficient bytecode
52
+ * Write an instruction-level optimizing compiler
53
+ * Experiment with and learn about Python bytecode
54
+ * Foil decompilers like uncompyle6_ so that they can’t disassemble bytecode (at least for now)
55
+
56
+ This support the same kinds of bytecode that xdis_ supports. This is
57
+ pretty much all released bytecode before Python 3.11. We tend to lag behind the
58
+ latest Python releases.
59
+
60
+ The code requires Python 3.6 or later.
61
+
62
+ Assembly files
63
+ --------------
64
+
65
+ See how-to-use_ for more detail. Some general some principles:
66
+
67
+ * Preferred extension for Python assembly is ``.pyasm``
68
+ * assembly is designed to work with the output of ``pydisasm -F xasm``
69
+ * Assembly file labels are at the beginning of the line
70
+ and end in a colon, e.g. ``END_IF:``
71
+ * instruction offsets in the assembly file are ignored and don't need
72
+ to be entered
73
+ * in those instructions that refer to offsets, if the if the
74
+ operand is an int, exactly that value will be used for the operand. Otherwise
75
+ we will look for labels and match up with that
76
+
77
+
78
+ Installation
79
+ ------------
80
+
81
+ *If you are using Python 3.11 or later*, you can install from PyPI using the name ``xasm``::
82
+
83
+ pip install xasm
84
+
85
+ A GNU makefile is also provided so ``make install`` (possibly as root or
86
+ sudo) will do the steps above.
87
+
88
+
89
+ *If you are using Python before 3.11*, do not install using PyPI, but instead install using a file in the `GitHub Releases section <https://github.com/rocky/python-xasm/releases>`_. Older Python used to use `easy_install <https://python101.pythonlibrary.org/chapter29_pip.html#using-easy-install>`_. But this is no longer supported in PyPi or newer Python versions. And vice versa, *poetry* nor *pip*, (the newer ways) are not supported on older Pythons.
90
+
91
+ If the Python version you are running xasm is between Python 3.6 through 3.11, use a tarball called xasm_36-*x.y.z*.tar.gz.
92
+
93
+ If the Python version you are running xasm is 3.11 or later, use a file called xasm-*x.y.z*.tar.gz.
94
+
95
+ Similarly, a tarball with or without the underscore *xx*, e.g., xasm_36-*x.y.z*.tar.gz. works only from Python 3.11 or greater.
96
+
97
+ Rationale for using Git Branches
98
+ ++++++++++++++++++++++++++++++++
99
+
100
+ It is currently impossible (if not impractical) to have one Python source code of this complexity and with this many features that can run both Python 3.6 and Python 3.13+. The languages have drifted so much, and packaging is vastly different.
101
+
102
+ A GNU makefile is also provided so :code:`make install` (possibly as root or sudo) will do the steps above.
103
+
104
+
105
+ Testing
106
+ -------
107
+
108
+ ::
109
+
110
+ make check
111
+
112
+ A GNU makefile has been added to smooth over setting running the right
113
+ command, and running tests from fastest to slowest.
114
+
115
+ If you have remake_ installed, you can see the list of all tasks
116
+ including tests via :code:`remake --tasks`.
117
+
118
+
119
+ Example Assembly File
120
+ ---------------------
121
+
122
+ For this Python source code:
123
+
124
+ ::
125
+
126
+ def five():
127
+ return 5
128
+
129
+ print(five())
130
+
131
+ Here is an assembly for the above:
132
+
133
+ ::
134
+
135
+ # Python bytecode 3.6 (3379)
136
+
137
+ # Method Name: five
138
+ # Filename: /tmp/five.pl
139
+ # Argument count: 0
140
+ # Kw-only arguments: 0
141
+ # Number of locals: 0
142
+ # Stack size: 1
143
+ # Flags: 0x00000043 (NOFREE | NEWLOCALS | OPTIMIZED)
144
+ # First Line: 1
145
+ # Constants:
146
+ # 0: None
147
+ # 1: 5
148
+ 2:
149
+ LOAD_CONST (5)
150
+ RETURN_VALUE
151
+
152
+
153
+ # Method Name: <module>
154
+ # Filename: /tmp/five.pl
155
+ # Argument count: 0
156
+ # Kw-only arguments: 0
157
+ # Number of locals: 0
158
+ # Stack size: 2
159
+ # Flags: 0x00000040 (NOFREE)
160
+ # First Line: 1
161
+ # Constants:
162
+ # 0: <code object five at 0x0000>
163
+ # 1: 'five'
164
+ # 2: None
165
+ # Names:
166
+ # 0: five
167
+ # 1: print
168
+ 1:
169
+ LOAD_CONST 0 (<code object five at 0x0000>)
170
+ LOAD_CONST ('five')
171
+ MAKE_FUNCTION 0
172
+ STORE_NAME (five)
173
+
174
+ 3:
175
+ LOAD_NAME (print)
176
+ LOAD_NAME (five)
177
+ CALL_FUNCTION 0
178
+ CALL_FUNCTION 1
179
+ POP_TOP
180
+ LOAD_CONST (None)
181
+ RETURN_VALUE
182
+
183
+
184
+ The above can be created automatically from Python source code using the ``pydisasm``
185
+ command from ``xdis``:
186
+
187
+ ::
188
+
189
+ pydisasm --format xasm /tmp/five.pyc
190
+
191
+ In the example above though, I have shortened and simplified the result.
192
+
193
+
194
+ Usage
195
+ -----
196
+
197
+ To create a python bytecode file from an assemble file, run:
198
+
199
+ ::
200
+
201
+ pyc-xasm [OPTIONS] ASM_PATH
202
+
203
+
204
+ For usage help, type: ``pyc-xasm --help``.
205
+
206
+
207
+ To convert a python bytecode from one bytecode to another, run:
208
+
209
+ ::
210
+
211
+ pyc-convert [OPTIONS] INPUT_PYC [OUTPUT_PYC]
212
+
213
+
214
+ For usage help, type: ``pyc-convert --help``.
215
+
216
+
217
+ See Also
218
+ --------
219
+
220
+ * https://github.com/rocky/python-xdis : Cross Python version disassemble
221
+ * https://github.com/rocky/x-python : Cross Python version interpreter
222
+ * https://github.com/rocky/python-xasm/blob/master/HOW-TO-USE.rst : How to write an assembler file
223
+ * https://rocky.github.io/pycon2018-light.co/ : Pycolumbia 2018 Lightning talk showing how to use the assembler
224
+
225
+
226
+ .. _uncompyle6: https://github.com/rocky/python-uncompyle6
227
+ .. _how-to-use: https://github.com/rocky/python-xasm/blob/master/HOW-TO-USE.rst
228
+ .. _xdis: https://github.com/rocky/xdis
229
+ .. |Latest Version| image:: https://badge.fury.io/py/xasm.svg
230
+ :target: https://badge.fury.io/py/xasm
231
+ .. |Pypi Installs| image:: https://pepy.tech/badge/xasm
232
+ .. |Supported Python Versions| image:: https://img.shields.io/pypi/pyversions/xasm.svg
233
+ .. _remake: http://bashdb.sf.net/remake
@@ -0,0 +1,13 @@
1
+ xasm/.gitignore,sha256=4M-0eEErWDaEphX2OA2Bsp72_sUTUkrs1LXr70HkItw,30
2
+ xasm/__init__.py,sha256=gz94OZ_Jc1WozfOYH1pjQeg7IgB1L9wv5fyytJ2XgZU,174
3
+ xasm/assemble.py,sha256=0l_0AlsQL2Pwp4ZAR8ucdC6CKnNjeZACc5pD6GORFis,26442
4
+ xasm/pyc_convert.py,sha256=s2UixbgUQZFHv9nmtvOV7TYohLBev2lcet0GIE9g6GM,9177
5
+ xasm/version.py,sha256=xEuuftKJb_Pe2D5lJpTv3HxDgx6Bd1-lH_6HBGWFguw,206
6
+ xasm/write_pyc.py,sha256=ZoqjupN9rEjJ5o49SZcX9rbEhaImnqsJKkNzLnT9j4c,1455
7
+ xasm/xasm_cli.py,sha256=4EYRZVejspzBvoNaXsWgGbN7qRU5p-MPrt05IYu1kGc,1789
8
+ xasm-1.2.1.dist-info/licenses/LICENSE.gpl2,sha256=2ylvL381vKOhdO-w6zkrOxe9lLNBhRQpo9_0EbHC_HM,18046
9
+ xasm-1.2.1.dist-info/METADATA,sha256=8iv_uKXBGELwvcM1oLGQRciIftEK9gcG0cqM3Is_mfM,7334
10
+ xasm-1.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
+ xasm-1.2.1.dist-info/entry_points.txt,sha256=3NCzOsGwLI-kMOKN72-joKrVjz8DAjHdw7aZof31A2E,50
12
+ xasm-1.2.1.dist-info/top_level.txt,sha256=24UNOItB5o_EJoJ9nqhPZEC5GiSaYtHll3F6mJXzOkA,5
13
+ xasm-1.2.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ python-cfg = xasm.__main__:main