├── AUTHORS
├── CONTRIBUTING.md
├── CONTRIBUTORS
├── LICENSE
├── Makefile
├── README.md
├── dynasm-driver.c
├── jit1.c
├── jit2.dasc
├── jit3.dasc
└── third_party
└── dynasm
├── LICENSE
├── README.google
├── dasm_arm.h
├── dasm_arm.lua
├── dasm_mips.h
├── dasm_mips.lua
├── dasm_ppc.h
├── dasm_ppc.lua
├── dasm_proto.h
├── dasm_x64.lua
├── dasm_x86.h
├── dasm_x86.lua
└── dynasm.lua
/AUTHORS:
--------------------------------------------------------------------------------
1 | # Copyright Holders.
2 |
3 | Google, Inc.
4 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Signing the CLA
2 |
3 | Please sign the [Google Contributor License Agreement
4 | (CLA)](https://cla.developers.google.com/)
5 | before sending pull requests. For any code changes to be
6 | accepted, the CLA must be signed. It's a quick process, I
7 | promise!
8 |
--------------------------------------------------------------------------------
/CONTRIBUTORS:
--------------------------------------------------------------------------------
1 | # People who have contributed code but are not copyright holders.
2 |
3 | Joshua Haberman
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 |
2 | CFLAGS=-O3 -g -std=gnu99 -Ithird_party
3 |
4 | all: jit1 jit2 jit3
5 |
6 | jit1: jit1.c
7 |
8 | jit2: dynasm-driver.c jit2.h
9 | $(CC) $(CFLAGS) $(CPPFLAGS) -o jit2 dynasm-driver.c -DJIT=\"jit2.h\"
10 | jit2.h: jit2.dasc
11 | lua dynasm/dynasm.lua jit2.dasc > jit2.h
12 |
13 | jit3: dynasm-driver.c jit3.h
14 | $(CC) $(CFLAGS) $(CPPFLAGS) -o jit3 dynasm-driver.c -DJIT=\"jit3.h\"
15 | jit3.h: jit3.dasc
16 | lua dynasm/dynasm.lua jit3.dasc > jit3.h
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | jitdemo
2 | =======
3 |
4 | Demo programs for my blog entry "Hello, JIT World!"
--------------------------------------------------------------------------------
/dynasm-driver.c:
--------------------------------------------------------------------------------
1 | // Driver file for DynASM-based JITs.
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include "dynasm/dasm_proto.h"
8 | #include "dynasm/dasm_x86.h"
9 |
10 | void initjit(dasm_State **state, const void *actionlist);
11 | void *jitcode(dasm_State **state);
12 | void free_jitcode(void *code);
13 |
14 | #include JIT
15 |
16 | void initjit(dasm_State **state, const void *actionlist) {
17 | dasm_init(state, 1);
18 | dasm_setup(state, actionlist);
19 | }
20 |
21 | void *jitcode(dasm_State **state) {
22 | size_t size;
23 | int dasm_status = dasm_link(state, &size);
24 | assert(dasm_status == DASM_S_OK);
25 |
26 | // Allocate memory readable and writable so we can
27 | // write the encoded instructions there.
28 | char *mem = mmap(NULL, size + sizeof(size_t),
29 | PROT_READ | PROT_WRITE,
30 | MAP_ANON | MAP_PRIVATE, -1, 0);
31 | assert(mem != MAP_FAILED);
32 |
33 | // Store length at the beginning of the region, so we
34 | // can free it without additional context.
35 | *(size_t*)mem = size;
36 | void *ret = mem + sizeof(size_t);
37 |
38 | dasm_encode(state, ret);
39 | dasm_free(state);
40 |
41 | // Adjust the memory permissions so it is executable
42 | // but no longer writable.
43 | int success = mprotect(mem, size, PROT_EXEC | PROT_READ);
44 | assert(success == 0);
45 |
46 | #ifndef NDEBUG
47 | // Write generated machine code to a temporary file.
48 | // View with:
49 | // objdump -D -b binary -mi386 -Mx86-64 /tmp/jitcode
50 | // Or:
51 | // ndisasm -b 64 /tmp/jitcode
52 | FILE *f = fopen("/tmp/jitcode", "wb");
53 | fwrite(ret, size, 1, f);
54 | fclose(f);
55 | #endif
56 |
57 | return ret;
58 | }
59 |
60 | void free_jitcode(void *code) {
61 | void *mem = (char*)code - sizeof(size_t);
62 | int status = munmap(mem, *(size_t*)mem);
63 | assert(status == 0);
64 | }
65 |
--------------------------------------------------------------------------------
/jit1.c:
--------------------------------------------------------------------------------
1 | // Most basic JIT; patches a partially-encoded function
2 | // and executes it.
3 | //
4 | // Only works on x86-64!
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | int main(int argc, char *argv[]) {
12 | // Machine code for:
13 | // mov eax, 0
14 | // ret
15 | unsigned char code[] = {0xb8, 0x00, 0x00, 0x00, 0x00, 0xc3};
16 |
17 | if (argc < 2) {
18 | fprintf(stderr, "Usage: jit1 \n");
19 | return 1;
20 | }
21 |
22 | // Overwrite immediate value "0" in the instruction
23 | // with the user's value. This will make our code:
24 | // mov eax,
25 | // ret
26 | int num = atoi(argv[1]);
27 | memcpy(&code[1], &num, 4);
28 |
29 | // Allocate writable/executable memory.
30 | // Note: real programs should not map memory both writable
31 | // and executable because it is a security risk.
32 | void *mem = mmap(NULL, sizeof(code), PROT_WRITE | PROT_EXEC,
33 | MAP_ANON | MAP_PRIVATE, -1, 0);
34 | memcpy(mem, code, sizeof(code));
35 |
36 | // The function will return the user's value.
37 | int (*func)() = mem;
38 | return func();
39 | }
40 |
--------------------------------------------------------------------------------
/jit2.dasc:
--------------------------------------------------------------------------------
1 | // Most basic DynASM JIT; generates a trivial function that
2 | // returns a given value, and executes it.
3 |
4 | // DynASM directives.
5 | |.arch x64
6 | |.actionlist actions
7 |
8 | // This define affects "|" DynASM lines. "Dst" must
9 | // resolve to a dasm_State** that points to a dasm_State*.
10 | #define Dst &state
11 |
12 | int main(int argc, char *argv[]) {
13 | if (argc < 2) {
14 | fprintf(stderr, "Usage: jit2 \n");
15 | return 1;
16 | }
17 |
18 | int num = atoi(argv[1]);
19 | dasm_State *state;
20 | initjit(&state, actions);
21 |
22 | // Generate the code. Each line appends to a buffer in
23 | // "state", but the code in this buffer is not fully linked
24 | // yet because labels can be referenced before they are
25 | // defined.
26 | //
27 | // The run-time value of C variable "num" is substituted
28 | // into the immediate value of the instruction.
29 | | mov eax, num
30 | | ret
31 |
32 | // Link the code and write it to executable memory.
33 | int (*fptr)() = jitcode(&state);
34 |
35 | // Call the JIT-ted function.
36 | int ret = fptr();
37 | assert(num == ret);
38 |
39 | // Free the machine code.
40 | free_jitcode(fptr);
41 |
42 | return ret;
43 | }
44 |
--------------------------------------------------------------------------------
/jit3.dasc:
--------------------------------------------------------------------------------
1 | // JIT for Brainf*ck.
2 |
3 | #include
4 |
5 | |.arch x64
6 | |.actionlist actions
7 | |
8 | |// Use rbx as our cell pointer.
9 | |// Since rbx is a callee-save register, it will be preserved
10 | |// across our calls to getchar and putchar.
11 | |.define PTR, rbx
12 | |
13 | |// Macro for calling a function.
14 | |// In cases where our target is <=2**32 away we can use
15 | |// | call &addr
16 | |// But since we don't know if it will be, we use this safe
17 | |// sequence instead.
18 | |.macro callp, addr
19 | | mov64 rax, (uintptr_t)addr
20 | | call rax
21 | |.endmacro
22 |
23 | #define Dst &state
24 | #define MAX_NESTING 256
25 |
26 | void err(const char *msg) {
27 | fprintf(stderr, "%s\n", msg);
28 | exit(1);
29 | }
30 |
31 | int main(int argc, char *argv[]) {
32 | if (argc < 2) err("Usage: jit3 ");
33 | dasm_State *state;
34 | initjit(&state, actions);
35 |
36 | unsigned int maxpc = 0;
37 | int pcstack[MAX_NESTING];
38 | int *top = pcstack, *limit = pcstack + MAX_NESTING;
39 |
40 | // Function prologue.
41 | | push PTR
42 | | mov PTR, rdi
43 |
44 | for (char *p = argv[1]; *p; p++) {
45 | switch (*p) {
46 | case '>':
47 | | inc PTR
48 | break;
49 | case '<':
50 | | dec PTR
51 | break;
52 | case '+':
53 | | inc byte [PTR]
54 | break;
55 | case '-':
56 | | dec byte [PTR]
57 | break;
58 | case '.':
59 | | movzx edi, byte [PTR]
60 | | callp putchar
61 | break;
62 | case ',':
63 | | callp getchar
64 | | mov byte [PTR], al
65 | break;
66 | case '[':
67 | if (top == limit) err("Nesting too deep.");
68 | // Each loop gets two pclabels: at the beginning and end.
69 | // We store pclabel offsets in a stack to link the loop
70 | // begin and end together.
71 | maxpc += 2;
72 | *top++ = maxpc;
73 | dasm_growpc(&state, maxpc);
74 | | cmp byte [PTR], 0
75 | | je =>(maxpc-2)
76 | |=>(maxpc-1):
77 | break;
78 | case ']':
79 | if (top == pcstack) err("Unmatched ']'");
80 | top--;
81 | | cmp byte [PTR], 0
82 | | jne =>(*top-1)
83 | |=>(*top-2):
84 | break;
85 | }
86 | }
87 |
88 | // Function epilogue.
89 | | pop PTR
90 | | ret
91 |
92 | void (*fptr)(char*) = jitcode(&state);
93 | char *mem = calloc(30000, 1);
94 | fptr(mem);
95 | free(mem);
96 | free_jitcode(fptr);
97 | return 0;
98 | }
99 |
--------------------------------------------------------------------------------
/third_party/dynasm/LICENSE:
--------------------------------------------------------------------------------
1 | ===============================================================================
2 | LuaJIT -- a Just-In-Time Compiler for Lua. http://luajit.org/
3 |
4 | Copyright (C) 2005-2011 Mike Pall. All rights reserved.
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
24 | [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
25 |
26 | ===============================================================================
27 | [ LuaJIT includes code from Lua 5.1/5.2, which has this license statement: ]
28 |
29 | Copyright (C) 1994-2011 Lua.org, PUC-Rio.
30 |
31 | Permission is hereby granted, free of charge, to any person obtaining a copy
32 | of this software and associated documentation files (the "Software"), to deal
33 | in the Software without restriction, including without limitation the rights
34 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35 | copies of the Software, and to permit persons to whom the Software is
36 | furnished to do so, subject to the following conditions:
37 |
38 | The above copyright notice and this permission notice shall be included in
39 | all copies or substantial portions of the Software.
40 |
41 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
46 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
47 | THE SOFTWARE.
48 |
49 | ===============================================================================
50 | [ LuaJIT includes code from dlmalloc, which has this license statement: ]
51 |
52 | This is a version (aka dlmalloc) of malloc/free/realloc written by
53 | Doug Lea and released to the public domain, as explained at
54 | http://creativecommons.org/licenses/publicdomain
55 |
56 | ===============================================================================
57 |
--------------------------------------------------------------------------------
/third_party/dynasm/README.google:
--------------------------------------------------------------------------------
1 | URL: http://repo.or.cz/w/luajit-2.0.git/tree/6c05739684527919293e25668589f17c35a7c129:/dynasm
2 | Version: 6c05739684527919293e25668589f17c35a7c129
3 | License: MIT
4 | License File: LICENSE
5 | Description:
6 | Taken from the larger LuaJIT project, DynASM is a tiny preprocessor and
7 | runtime for generating machine code at runtime.
8 |
9 | Local Modifications:
10 | No modifications.
11 |
--------------------------------------------------------------------------------
/third_party/dynasm/dasm_arm.h:
--------------------------------------------------------------------------------
1 | /*
2 | ** DynASM ARM encoding engine.
3 | ** Copyright (C) 2005-2012 Mike Pall. All rights reserved.
4 | ** Released under the MIT license. See dynasm.lua for full copyright notice.
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #define DASM_ARCH "arm"
13 |
14 | #ifndef DASM_EXTERN
15 | #define DASM_EXTERN(a,b,c,d) 0
16 | #endif
17 |
18 | /* Action definitions. */
19 | enum {
20 | DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
21 | /* The following actions need a buffer position. */
22 | DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
23 | /* The following actions also have an argument. */
24 | DASM_REL_PC, DASM_LABEL_PC,
25 | DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12,
26 | DASM__MAX
27 | };
28 |
29 | /* Maximum number of section buffer positions for a single dasm_put() call. */
30 | #define DASM_MAXSECPOS 25
31 |
32 | /* DynASM encoder status codes. Action list offset or number are or'ed in. */
33 | #define DASM_S_OK 0x00000000
34 | #define DASM_S_NOMEM 0x01000000
35 | #define DASM_S_PHASE 0x02000000
36 | #define DASM_S_MATCH_SEC 0x03000000
37 | #define DASM_S_RANGE_I 0x11000000
38 | #define DASM_S_RANGE_SEC 0x12000000
39 | #define DASM_S_RANGE_LG 0x13000000
40 | #define DASM_S_RANGE_PC 0x14000000
41 | #define DASM_S_RANGE_REL 0x15000000
42 | #define DASM_S_UNDEF_LG 0x21000000
43 | #define DASM_S_UNDEF_PC 0x22000000
44 |
45 | /* Macros to convert positions (8 bit section + 24 bit index). */
46 | #define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
47 | #define DASM_POS2BIAS(pos) ((pos)&0xff000000)
48 | #define DASM_SEC2POS(sec) ((sec)<<24)
49 | #define DASM_POS2SEC(pos) ((pos)>>24)
50 | #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
51 |
52 | /* Action list type. */
53 | typedef const unsigned int *dasm_ActList;
54 |
55 | /* Per-section structure. */
56 | typedef struct dasm_Section {
57 | int *rbuf; /* Biased buffer pointer (negative section bias). */
58 | int *buf; /* True buffer pointer. */
59 | size_t bsize; /* Buffer size in bytes. */
60 | int pos; /* Biased buffer position. */
61 | int epos; /* End of biased buffer position - max single put. */
62 | int ofs; /* Byte offset into section. */
63 | } dasm_Section;
64 |
65 | /* Core structure holding the DynASM encoding state. */
66 | struct dasm_State {
67 | size_t psize; /* Allocated size of this structure. */
68 | dasm_ActList actionlist; /* Current actionlist pointer. */
69 | int *lglabels; /* Local/global chain/pos ptrs. */
70 | size_t lgsize;
71 | int *pclabels; /* PC label chains/pos ptrs. */
72 | size_t pcsize;
73 | void **globals; /* Array of globals (bias -10). */
74 | dasm_Section *section; /* Pointer to active section. */
75 | size_t codesize; /* Total size of all code sections. */
76 | int maxsection; /* 0 <= sectionidx < maxsection. */
77 | int status; /* Status code. */
78 | dasm_Section sections[1]; /* All sections. Alloc-extended. */
79 | };
80 |
81 | /* The size of the core structure depends on the max. number of sections. */
82 | #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
83 |
84 |
85 | /* Initialize DynASM state. */
86 | void dasm_init(Dst_DECL, int maxsection)
87 | {
88 | dasm_State *D;
89 | size_t psz = 0;
90 | int i;
91 | Dst_REF = NULL;
92 | DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
93 | D = Dst_REF;
94 | D->psize = psz;
95 | D->lglabels = NULL;
96 | D->lgsize = 0;
97 | D->pclabels = NULL;
98 | D->pcsize = 0;
99 | D->globals = NULL;
100 | D->maxsection = maxsection;
101 | for (i = 0; i < maxsection; i++) {
102 | D->sections[i].buf = NULL; /* Need this for pass3. */
103 | D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
104 | D->sections[i].bsize = 0;
105 | D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
106 | }
107 | }
108 |
109 | /* Free DynASM state. */
110 | void dasm_free(Dst_DECL)
111 | {
112 | dasm_State *D = Dst_REF;
113 | int i;
114 | for (i = 0; i < D->maxsection; i++)
115 | if (D->sections[i].buf)
116 | DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
117 | if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
118 | if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
119 | DASM_M_FREE(Dst, D, D->psize);
120 | }
121 |
122 | /* Setup global label array. Must be called before dasm_setup(). */
123 | void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
124 | {
125 | dasm_State *D = Dst_REF;
126 | D->globals = gl - 10; /* Negative bias to compensate for locals. */
127 | DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
128 | }
129 |
130 | /* Grow PC label array. Can be called after dasm_setup(), too. */
131 | void dasm_growpc(Dst_DECL, unsigned int maxpc)
132 | {
133 | dasm_State *D = Dst_REF;
134 | size_t osz = D->pcsize;
135 | DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
136 | memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
137 | }
138 |
139 | /* Setup encoder. */
140 | void dasm_setup(Dst_DECL, const void *actionlist)
141 | {
142 | dasm_State *D = Dst_REF;
143 | int i;
144 | D->actionlist = (dasm_ActList)actionlist;
145 | D->status = DASM_S_OK;
146 | D->section = &D->sections[0];
147 | memset((void *)D->lglabels, 0, D->lgsize);
148 | if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
149 | for (i = 0; i < D->maxsection; i++) {
150 | D->sections[i].pos = DASM_SEC2POS(i);
151 | D->sections[i].ofs = 0;
152 | }
153 | }
154 |
155 |
156 | #ifdef DASM_CHECKS
157 | #define CK(x, st) \
158 | do { if (!(x)) { \
159 | D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
160 | #define CKPL(kind, st) \
161 | do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
162 | D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
163 | #else
164 | #define CK(x, st) ((void)0)
165 | #define CKPL(kind, st) ((void)0)
166 | #endif
167 |
168 | static int dasm_imm12(unsigned int n)
169 | {
170 | int i;
171 | for (i = 0; i < 16; i++, n = (n << 2) | (n >> 30))
172 | if (n <= 255) return (int)(n + (i << 8));
173 | return -1;
174 | }
175 |
176 | /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
177 | void dasm_put(Dst_DECL, int start, ...)
178 | {
179 | va_list ap;
180 | dasm_State *D = Dst_REF;
181 | dasm_ActList p = D->actionlist + start;
182 | dasm_Section *sec = D->section;
183 | int pos = sec->pos, ofs = sec->ofs;
184 | int *b;
185 |
186 | if (pos >= sec->epos) {
187 | DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
188 | sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
189 | sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
190 | sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
191 | }
192 |
193 | b = sec->rbuf;
194 | b[pos++] = start;
195 |
196 | va_start(ap, start);
197 | while (1) {
198 | unsigned int ins = *p++;
199 | unsigned int action = (ins >> 16);
200 | if (action >= DASM__MAX) {
201 | ofs += 4;
202 | } else {
203 | int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
204 | switch (action) {
205 | case DASM_STOP: goto stop;
206 | case DASM_SECTION:
207 | n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
208 | D->section = &D->sections[n]; goto stop;
209 | case DASM_ESC: p++; ofs += 4; break;
210 | case DASM_REL_EXT: break;
211 | case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
212 | case DASM_REL_LG:
213 | n = (ins & 2047) - 10; pl = D->lglabels + n;
214 | if (n >= 0) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */
215 | pl += 10; n = *pl;
216 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
217 | goto linkrel;
218 | case DASM_REL_PC:
219 | pl = D->pclabels + n; CKPL(pc, PC);
220 | putrel:
221 | n = *pl;
222 | if (n < 0) { /* Label exists. Get label pos and store it. */
223 | b[pos] = -n;
224 | } else {
225 | linkrel:
226 | b[pos] = n; /* Else link to rel chain, anchored at label. */
227 | *pl = pos;
228 | }
229 | pos++;
230 | break;
231 | case DASM_LABEL_LG:
232 | pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
233 | case DASM_LABEL_PC:
234 | pl = D->pclabels + n; CKPL(pc, PC);
235 | putlabel:
236 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
237 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
238 | }
239 | *pl = -pos; /* Label exists now. */
240 | b[pos++] = ofs; /* Store pass1 offset estimate. */
241 | break;
242 | case DASM_IMM:
243 | case DASM_IMM16:
244 | #ifdef DASM_CHECKS
245 | CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
246 | if ((ins & 0x8000))
247 | CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
248 | else
249 | CK((n>>((ins>>5)&31)) == 0, RANGE_I);
250 | #endif
251 | b[pos++] = n;
252 | break;
253 | case DASM_IMML8:
254 | case DASM_IMML12:
255 | CK(n >= 0 ? ((n>>((ins>>5)&31)) == 0) :
256 | (((-n)>>((ins>>5)&31)) == 0), RANGE_I);
257 | b[pos++] = n;
258 | break;
259 | case DASM_IMM12:
260 | CK(dasm_imm12((unsigned int)n) != -1, RANGE_I);
261 | b[pos++] = n;
262 | break;
263 | }
264 | }
265 | }
266 | stop:
267 | va_end(ap);
268 | sec->pos = pos;
269 | sec->ofs = ofs;
270 | }
271 | #undef CK
272 |
273 | /* Pass 2: Link sections, shrink aligns, fix label offsets. */
274 | int dasm_link(Dst_DECL, size_t *szp)
275 | {
276 | dasm_State *D = Dst_REF;
277 | int secnum;
278 | int ofs = 0;
279 |
280 | #ifdef DASM_CHECKS
281 | *szp = 0;
282 | if (D->status != DASM_S_OK) return D->status;
283 | {
284 | int pc;
285 | for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
286 | if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
287 | }
288 | #endif
289 |
290 | { /* Handle globals not defined in this translation unit. */
291 | int idx;
292 | for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
293 | int n = D->lglabels[idx];
294 | /* Undefined label: Collapse rel chain and replace with marker (< 0). */
295 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
296 | }
297 | }
298 |
299 | /* Combine all code sections. No support for data sections (yet). */
300 | for (secnum = 0; secnum < D->maxsection; secnum++) {
301 | dasm_Section *sec = D->sections + secnum;
302 | int *b = sec->rbuf;
303 | int pos = DASM_SEC2POS(secnum);
304 | int lastpos = sec->pos;
305 |
306 | while (pos != lastpos) {
307 | dasm_ActList p = D->actionlist + b[pos++];
308 | while (1) {
309 | unsigned int ins = *p++;
310 | unsigned int action = (ins >> 16);
311 | switch (action) {
312 | case DASM_STOP: case DASM_SECTION: goto stop;
313 | case DASM_ESC: p++; break;
314 | case DASM_REL_EXT: break;
315 | case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
316 | case DASM_REL_LG: case DASM_REL_PC: pos++; break;
317 | case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
318 | case DASM_IMM: case DASM_IMM12: case DASM_IMM16:
319 | case DASM_IMML8: case DASM_IMML12: pos++; break;
320 | }
321 | }
322 | stop: (void)0;
323 | }
324 | ofs += sec->ofs; /* Next section starts right after current section. */
325 | }
326 |
327 | D->codesize = ofs; /* Total size of all code sections */
328 | *szp = ofs;
329 | return DASM_S_OK;
330 | }
331 |
332 | #ifdef DASM_CHECKS
333 | #define CK(x, st) \
334 | do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
335 | #else
336 | #define CK(x, st) ((void)0)
337 | #endif
338 |
339 | /* Pass 3: Encode sections. */
340 | int dasm_encode(Dst_DECL, void *buffer)
341 | {
342 | dasm_State *D = Dst_REF;
343 | char *base = (char *)buffer;
344 | unsigned int *cp = (unsigned int *)buffer;
345 | int secnum;
346 |
347 | /* Encode all code sections. No support for data sections (yet). */
348 | for (secnum = 0; secnum < D->maxsection; secnum++) {
349 | dasm_Section *sec = D->sections + secnum;
350 | int *b = sec->buf;
351 | int *endb = sec->rbuf + sec->pos;
352 |
353 | while (b != endb) {
354 | dasm_ActList p = D->actionlist + *b++;
355 | while (1) {
356 | unsigned int ins = *p++;
357 | unsigned int action = (ins >> 16);
358 | int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
359 | switch (action) {
360 | case DASM_STOP: case DASM_SECTION: goto stop;
361 | case DASM_ESC: *cp++ = *p++; break;
362 | case DASM_REL_EXT:
363 | n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048));
364 | goto patchrel;
365 | case DASM_ALIGN:
366 | ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000;
367 | break;
368 | case DASM_REL_LG:
369 | CK(n >= 0, UNDEF_LG);
370 | case DASM_REL_PC:
371 | CK(n >= 0, UNDEF_PC);
372 | n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) - 4;
373 | patchrel:
374 | if ((ins & 0x800) == 0) {
375 | CK((n & 3) == 0 && ((n+0x02000000) >> 26) == 0, RANGE_REL);
376 | cp[-1] |= ((n >> 2) & 0x00ffffff);
377 | } else if ((ins & 0x1000)) {
378 | CK((n & 3) == 0 && -256 <= n && n <= 256, RANGE_REL);
379 | goto patchimml8;
380 | } else {
381 | CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL);
382 | goto patchimml12;
383 | }
384 | break;
385 | case DASM_LABEL_LG:
386 | ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
387 | break;
388 | case DASM_LABEL_PC: break;
389 | case DASM_IMM:
390 | cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31);
391 | break;
392 | case DASM_IMM12:
393 | cp[-1] |= dasm_imm12((unsigned int)n);
394 | break;
395 | case DASM_IMM16:
396 | cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff);
397 | break;
398 | case DASM_IMML8: patchimml8:
399 | cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) :
400 | ((-n & 0x0f) | ((-n & 0xf0) << 4));
401 | break;
402 | case DASM_IMML12: patchimml12:
403 | cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n);
404 | break;
405 | default: *cp++ = ins; break;
406 | }
407 | }
408 | stop: (void)0;
409 | }
410 | }
411 |
412 | if (base + D->codesize != (char *)cp) /* Check for phase errors. */
413 | return DASM_S_PHASE;
414 | return DASM_S_OK;
415 | }
416 | #undef CK
417 |
418 | /* Get PC label offset. */
419 | int dasm_getpclabel(Dst_DECL, unsigned int pc)
420 | {
421 | dasm_State *D = Dst_REF;
422 | if (pc*sizeof(int) < D->pcsize) {
423 | int pos = D->pclabels[pc];
424 | if (pos < 0) return *DASM_POS2PTR(D, -pos);
425 | if (pos > 0) return -1; /* Undefined. */
426 | }
427 | return -2; /* Unused or out of range. */
428 | }
429 |
430 | #ifdef DASM_CHECKS
431 | /* Optional sanity checker to call between isolated encoding steps. */
432 | int dasm_checkstep(Dst_DECL, int secmatch)
433 | {
434 | dasm_State *D = Dst_REF;
435 | if (D->status == DASM_S_OK) {
436 | int i;
437 | for (i = 1; i <= 9; i++) {
438 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
439 | D->lglabels[i] = 0;
440 | }
441 | }
442 | if (D->status == DASM_S_OK && secmatch >= 0 &&
443 | D->section != &D->sections[secmatch])
444 | D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
445 | return D->status;
446 | }
447 | #endif
448 |
449 |
--------------------------------------------------------------------------------
/third_party/dynasm/dasm_arm.lua:
--------------------------------------------------------------------------------
1 | ------------------------------------------------------------------------------
2 | -- DynASM ARM module.
3 | --
4 | -- Copyright (C) 2005-2012 Mike Pall. All rights reserved.
5 | -- See dynasm.lua for full copyright notice.
6 | ------------------------------------------------------------------------------
7 |
8 | -- Module information:
9 | local _info = {
10 | arch = "arm",
11 | description = "DynASM ARM module",
12 | version = "1.3.0",
13 | vernum = 10300,
14 | release = "2011-05-05",
15 | author = "Mike Pall",
16 | license = "MIT",
17 | }
18 |
19 | -- Exported glue functions for the arch-specific module.
20 | local _M = { _info = _info }
21 |
22 | -- Cache library functions.
23 | local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
24 | local assert, setmetatable, rawget = assert, setmetatable, rawget
25 | local _s = string
26 | local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
27 | local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub
28 | local concat, sort, insert = table.concat, table.sort, table.insert
29 |
30 | -- Inherited tables and callbacks.
31 | local g_opt, g_arch
32 | local wline, werror, wfatal, wwarn
33 |
34 | -- Action name list.
35 | -- CHECK: Keep this in sync with the C code!
36 | local action_names = {
37 | "STOP", "SECTION", "ESC", "REL_EXT",
38 | "ALIGN", "REL_LG", "LABEL_LG",
39 | "REL_PC", "LABEL_PC", "IMM", "IMM12", "IMM16", "IMML8", "IMML12",
40 | }
41 |
42 | -- Maximum number of section buffer positions for dasm_put().
43 | -- CHECK: Keep this in sync with the C code!
44 | local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
45 |
46 | -- Action name -> action number.
47 | local map_action = {}
48 | for n,name in ipairs(action_names) do
49 | map_action[name] = n-1
50 | end
51 |
52 | -- Action list buffer.
53 | local actlist = {}
54 |
55 | -- Argument list for next dasm_put(). Start with offset 0 into action list.
56 | local actargs = { 0 }
57 |
58 | -- Current number of section buffer positions for dasm_put().
59 | local secpos = 1
60 |
61 | ------------------------------------------------------------------------------
62 |
63 | -- Return 8 digit hex number.
64 | local function tohex(x)
65 | return sub(format("%08x", x), -8) -- Avoid 64 bit portability problem in Lua.
66 | end
67 |
68 | -- Dump action names and numbers.
69 | local function dumpactions(out)
70 | out:write("DynASM encoding engine action codes:\n")
71 | for n,name in ipairs(action_names) do
72 | local num = map_action[name]
73 | out:write(format(" %-10s %02X %d\n", name, num, num))
74 | end
75 | out:write("\n")
76 | end
77 |
78 | -- Write action list buffer as a huge static C array.
79 | local function writeactions(out, name)
80 | local nn = #actlist
81 | if nn == 0 then nn = 1; actlist[0] = map_action.STOP end
82 | out:write("static const unsigned int ", name, "[", nn, "] = {\n")
83 | for i = 1,nn-1 do
84 | assert(out:write("0x", tohex(actlist[i]), ",\n"))
85 | end
86 | assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n"))
87 | end
88 |
89 | ------------------------------------------------------------------------------
90 |
91 | -- Add word to action list.
92 | local function wputxw(n)
93 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
94 | actlist[#actlist+1] = n
95 | end
96 |
97 | -- Add action to list with optional arg. Advance buffer pos, too.
98 | local function waction(action, val, a, num)
99 | local w = assert(map_action[action], "bad action name `"..action.."'")
100 | wputxw(w * 0x10000 + (val or 0))
101 | if a then actargs[#actargs+1] = a end
102 | if a or num then secpos = secpos + (num or 1) end
103 | end
104 |
105 | -- Flush action list (intervening C code or buffer pos overflow).
106 | local function wflush(term)
107 | if #actlist == actargs[1] then return end -- Nothing to flush.
108 | if not term then waction("STOP") end -- Terminate action list.
109 | wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true)
110 | actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
111 | secpos = 1 -- The actionlist offset occupies a buffer position, too.
112 | end
113 |
114 | -- Put escaped word.
115 | local function wputw(n)
116 | if n <= 0x000fffff then waction("ESC") end
117 | wputxw(n)
118 | end
119 |
120 | -- Reserve position for word.
121 | local function wpos()
122 | local pos = #actlist+1
123 | actlist[pos] = ""
124 | return pos
125 | end
126 |
127 | -- Store word to reserved position.
128 | local function wputpos(pos, n)
129 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
130 | if n <= 0x000fffff then
131 | insert(actlist, pos+1, n)
132 | n = map_action.ESC * 0x10000
133 | end
134 | actlist[pos] = n
135 | end
136 |
137 | ------------------------------------------------------------------------------
138 |
139 | -- Global label name -> global label number. With auto assignment on 1st use.
140 | local next_global = 20
141 | local map_global = setmetatable({}, { __index = function(t, name)
142 | if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
143 | local n = next_global
144 | if n > 2047 then werror("too many global labels") end
145 | next_global = n + 1
146 | t[name] = n
147 | return n
148 | end})
149 |
150 | -- Dump global labels.
151 | local function dumpglobals(out, lvl)
152 | local t = {}
153 | for name, n in pairs(map_global) do t[n] = name end
154 | out:write("Global labels:\n")
155 | for i=20,next_global-1 do
156 | out:write(format(" %s\n", t[i]))
157 | end
158 | out:write("\n")
159 | end
160 |
161 | -- Write global label enum.
162 | local function writeglobals(out, prefix)
163 | local t = {}
164 | for name, n in pairs(map_global) do t[n] = name end
165 | out:write("enum {\n")
166 | for i=20,next_global-1 do
167 | out:write(" ", prefix, t[i], ",\n")
168 | end
169 | out:write(" ", prefix, "_MAX\n};\n")
170 | end
171 |
172 | -- Write global label names.
173 | local function writeglobalnames(out, name)
174 | local t = {}
175 | for name, n in pairs(map_global) do t[n] = name end
176 | out:write("static const char *const ", name, "[] = {\n")
177 | for i=20,next_global-1 do
178 | out:write(" \"", t[i], "\",\n")
179 | end
180 | out:write(" (const char *)0\n};\n")
181 | end
182 |
183 | ------------------------------------------------------------------------------
184 |
185 | -- Extern label name -> extern label number. With auto assignment on 1st use.
186 | local next_extern = 0
187 | local map_extern_ = {}
188 | local map_extern = setmetatable({}, { __index = function(t, name)
189 | -- No restrictions on the name for now.
190 | local n = next_extern
191 | if n > 2047 then werror("too many extern labels") end
192 | next_extern = n + 1
193 | t[name] = n
194 | map_extern_[n] = name
195 | return n
196 | end})
197 |
198 | -- Dump extern labels.
199 | local function dumpexterns(out, lvl)
200 | out:write("Extern labels:\n")
201 | for i=0,next_extern-1 do
202 | out:write(format(" %s\n", map_extern_[i]))
203 | end
204 | out:write("\n")
205 | end
206 |
207 | -- Write extern label names.
208 | local function writeexternnames(out, name)
209 | out:write("static const char *const ", name, "[] = {\n")
210 | for i=0,next_extern-1 do
211 | out:write(" \"", map_extern_[i], "\",\n")
212 | end
213 | out:write(" (const char *)0\n};\n")
214 | end
215 |
216 | ------------------------------------------------------------------------------
217 |
218 | -- Arch-specific maps.
219 |
220 | -- Ext. register name -> int. name.
221 | local map_archdef = { sp = "r13", lr = "r14", pc = "r15", }
222 |
223 | -- Int. register name -> ext. name.
224 | local map_reg_rev = { r13 = "sp", r14 = "lr", r15 = "pc", }
225 |
226 | local map_type = {} -- Type name -> { ctype, reg }
227 | local ctypenum = 0 -- Type number (for Dt... macros).
228 |
229 | -- Reverse defines for registers.
230 | function _M.revdef(s)
231 | return map_reg_rev[s] or s
232 | end
233 |
234 | local map_shift = { lsl = 0, lsr = 1, asr = 2, ror = 3, }
235 |
236 | local map_cond = {
237 | eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7,
238 | hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14,
239 | hs = 2, lo = 3,
240 | }
241 |
242 | ------------------------------------------------------------------------------
243 |
244 | -- Template strings for ARM instructions.
245 | local map_op = {
246 | -- Basic data processing instructions.
247 | and_3 = "e0000000DNPs",
248 | eor_3 = "e0200000DNPs",
249 | sub_3 = "e0400000DNPs",
250 | rsb_3 = "e0600000DNPs",
251 | add_3 = "e0800000DNPs",
252 | adc_3 = "e0a00000DNPs",
253 | sbc_3 = "e0c00000DNPs",
254 | rsc_3 = "e0e00000DNPs",
255 | tst_2 = "e1100000NP",
256 | teq_2 = "e1300000NP",
257 | cmp_2 = "e1500000NP",
258 | cmn_2 = "e1700000NP",
259 | orr_3 = "e1800000DNPs",
260 | mov_2 = "e1a00000DPs",
261 | bic_3 = "e1c00000DNPs",
262 | mvn_2 = "e1e00000DPs",
263 |
264 | and_4 = "e0000000DNMps",
265 | eor_4 = "e0200000DNMps",
266 | sub_4 = "e0400000DNMps",
267 | rsb_4 = "e0600000DNMps",
268 | add_4 = "e0800000DNMps",
269 | adc_4 = "e0a00000DNMps",
270 | sbc_4 = "e0c00000DNMps",
271 | rsc_4 = "e0e00000DNMps",
272 | tst_3 = "e1100000NMp",
273 | teq_3 = "e1300000NMp",
274 | cmp_3 = "e1500000NMp",
275 | cmn_3 = "e1700000NMp",
276 | orr_4 = "e1800000DNMps",
277 | mov_3 = "e1a00000DMps",
278 | bic_4 = "e1c00000DNMps",
279 | mvn_3 = "e1e00000DMps",
280 |
281 | lsl_3 = "e1a00000DMws",
282 | lsr_3 = "e1a00020DMws",
283 | asr_3 = "e1a00040DMws",
284 | ror_3 = "e1a00060DMws",
285 | rrx_2 = "e1a00060DMs",
286 |
287 | -- Multiply and multiply-accumulate.
288 | mul_3 = "e0000090NMSs",
289 | mla_4 = "e0200090NMSDs",
290 | umaal_4 = "e0400090DNMSs", -- v6
291 | mls_4 = "e0600090DNMSs", -- v6T2
292 | umull_4 = "e0800090DNMSs",
293 | umlal_4 = "e0a00090DNMSs",
294 | smull_4 = "e0c00090DNMSs",
295 | smlal_4 = "e0e00090DNMSs",
296 |
297 | -- Halfword multiply and multiply-accumulate.
298 | smlabb_4 = "e1000080NMSD", -- v5TE
299 | smlatb_4 = "e10000a0NMSD", -- v5TE
300 | smlabt_4 = "e10000c0NMSD", -- v5TE
301 | smlatt_4 = "e10000e0NMSD", -- v5TE
302 | smlawb_4 = "e1200080NMSD", -- v5TE
303 | smulwb_3 = "e12000a0NMS", -- v5TE
304 | smlawt_4 = "e12000c0NMSD", -- v5TE
305 | smulwt_3 = "e12000e0NMS", -- v5TE
306 | smlalbb_4 = "e1400080NMSD", -- v5TE
307 | smlaltb_4 = "e14000a0NMSD", -- v5TE
308 | smlalbt_4 = "e14000c0NMSD", -- v5TE
309 | smlaltt_4 = "e14000e0NMSD", -- v5TE
310 | smulbb_3 = "e1600080NMS", -- v5TE
311 | smultb_3 = "e16000a0NMS", -- v5TE
312 | smulbt_3 = "e16000c0NMS", -- v5TE
313 | smultt_3 = "e16000e0NMS", -- v5TE
314 |
315 | -- Miscellaneous data processing instructions.
316 | clz_2 = "e16f0f10DM", -- v5T
317 | rev_2 = "e6bf0f30DM", -- v6
318 | rev16_2 = "e6bf0fb0DM", -- v6
319 | revsh_2 = "e6ff0fb0DM", -- v6
320 | sel_3 = "e6800fb0DNM", -- v6
321 | usad8_3 = "e780f010NMS", -- v6
322 | usada8_4 = "e7800010NMSD", -- v6
323 | rbit_2 = "e6ff0f30DM", -- v6T2
324 | movw_2 = "e3000000DW", -- v6T2
325 | movt_2 = "e3400000DW", -- v6T2
326 | -- Note: the X encodes width-1, not width.
327 | sbfx_4 = "e7a00050DMvX", -- v6T2
328 | ubfx_4 = "e7e00050DMvX", -- v6T2
329 | -- Note: the X encodes the msb field, not the width.
330 | bfc_3 = "e7c0001fDvX", -- v6T2
331 | bfi_4 = "e7c00010DMvX", -- v6T2
332 |
333 | -- Packing and unpacking instructions.
334 | pkhbt_3 = "e6800010DNM", pkhbt_4 = "e6800010DNMv", -- v6
335 | pkhtb_3 = "e6800050DNM", pkhtb_4 = "e6800050DNMv", -- v6
336 | sxtab_3 = "e6a00070DNM", sxtab_4 = "e6a00070DNMv", -- v6
337 | sxtab16_3 = "e6800070DNM", sxtab16_4 = "e6800070DNMv", -- v6
338 | sxtah_3 = "e6b00070DNM", sxtah_4 = "e6b00070DNMv", -- v6
339 | sxtb_2 = "e6af0070DM", sxtb_3 = "e6af0070DMv", -- v6
340 | sxtb16_2 = "e68f0070DM", sxtb16_3 = "e68f0070DMv", -- v6
341 | sxth_2 = "e6bf0070DM", sxth_3 = "e6bf0070DMv", -- v6
342 | uxtab_3 = "e6e00070DNM", uxtab_4 = "e6e00070DNMv", -- v6
343 | uxtab16_3 = "e6c00070DNM", uxtab16_4 = "e6c00070DNMv", -- v6
344 | uxtah_3 = "e6f00070DNM", uxtah_4 = "e6f00070DNMv", -- v6
345 | uxtb_2 = "e6ef0070DM", uxtb_3 = "e6ef0070DMv", -- v6
346 | uxtb16_2 = "e6cf0070DM", uxtb16_3 = "e6cf0070DMv", -- v6
347 | uxth_2 = "e6ff0070DM", uxth_3 = "e6ff0070DMv", -- v6
348 |
349 | -- Saturating instructions.
350 | qadd_3 = "e1000050DMN", -- v5TE
351 | qsub_3 = "e1200050DMN", -- v5TE
352 | qdadd_3 = "e1400050DMN", -- v5TE
353 | qdsub_3 = "e1600050DMN", -- v5TE
354 | -- Note: the X for ssat* encodes sat_imm-1, not sat_imm.
355 | ssat_3 = "e6a00010DXM", ssat_4 = "e6a00010DXMp", -- v6
356 | usat_3 = "e6e00010DXM", usat_4 = "e6e00010DXMp", -- v6
357 | ssat16_3 = "e6a00f30DXM", -- v6
358 | usat16_3 = "e6e00f30DXM", -- v6
359 |
360 | -- Parallel addition and subtraction.
361 | sadd16_3 = "e6100f10DNM", -- v6
362 | sasx_3 = "e6100f30DNM", -- v6
363 | ssax_3 = "e6100f50DNM", -- v6
364 | ssub16_3 = "e6100f70DNM", -- v6
365 | sadd8_3 = "e6100f90DNM", -- v6
366 | ssub8_3 = "e6100ff0DNM", -- v6
367 | qadd16_3 = "e6200f10DNM", -- v6
368 | qasx_3 = "e6200f30DNM", -- v6
369 | qsax_3 = "e6200f50DNM", -- v6
370 | qsub16_3 = "e6200f70DNM", -- v6
371 | qadd8_3 = "e6200f90DNM", -- v6
372 | qsub8_3 = "e6200ff0DNM", -- v6
373 | shadd16_3 = "e6300f10DNM", -- v6
374 | shasx_3 = "e6300f30DNM", -- v6
375 | shsax_3 = "e6300f50DNM", -- v6
376 | shsub16_3 = "e6300f70DNM", -- v6
377 | shadd8_3 = "e6300f90DNM", -- v6
378 | shsub8_3 = "e6300ff0DNM", -- v6
379 | uadd16_3 = "e6500f10DNM", -- v6
380 | uasx_3 = "e6500f30DNM", -- v6
381 | usax_3 = "e6500f50DNM", -- v6
382 | usub16_3 = "e6500f70DNM", -- v6
383 | uadd8_3 = "e6500f90DNM", -- v6
384 | usub8_3 = "e6500ff0DNM", -- v6
385 | uqadd16_3 = "e6600f10DNM", -- v6
386 | uqasx_3 = "e6600f30DNM", -- v6
387 | uqsax_3 = "e6600f50DNM", -- v6
388 | uqsub16_3 = "e6600f70DNM", -- v6
389 | uqadd8_3 = "e6600f90DNM", -- v6
390 | uqsub8_3 = "e6600ff0DNM", -- v6
391 | uhadd16_3 = "e6700f10DNM", -- v6
392 | uhasx_3 = "e6700f30DNM", -- v6
393 | uhsax_3 = "e6700f50DNM", -- v6
394 | uhsub16_3 = "e6700f70DNM", -- v6
395 | uhadd8_3 = "e6700f90DNM", -- v6
396 | uhsub8_3 = "e6700ff0DNM", -- v6
397 |
398 | -- Load/store instructions.
399 | str_2 = "e4000000DL", str_3 = "e4000000DL", str_4 = "e4000000DL",
400 | strb_2 = "e4400000DL", strb_3 = "e4400000DL", strb_4 = "e4400000DL",
401 | ldr_2 = "e4100000DL", ldr_3 = "e4100000DL", ldr_4 = "e4100000DL",
402 | ldrb_2 = "e4500000DL", ldrb_3 = "e4500000DL", ldrb_4 = "e4500000DL",
403 | strh_2 = "e00000b0DL", strh_3 = "e00000b0DL",
404 | ldrh_2 = "e01000b0DL", ldrh_3 = "e01000b0DL",
405 | ldrd_2 = "e00000d0DL", ldrd_3 = "e00000d0DL", -- v5TE
406 | ldrsb_2 = "e01000d0DL", ldrsb_3 = "e01000d0DL",
407 | strd_2 = "e00000f0DL", strd_3 = "e00000f0DL", -- v5TE
408 | ldrsh_2 = "e01000f0DL", ldrsh_3 = "e01000f0DL",
409 |
410 | ldm_2 = "e8900000nR", ldmia_2 = "e8900000nR", ldmfd_2 = "e8900000nR",
411 | ldmda_2 = "e8100000nR", ldmfa_2 = "e8100000nR",
412 | ldmdb_2 = "e9100000nR", ldmea_2 = "e9100000nR",
413 | ldmib_2 = "e9900000nR", ldmed_2 = "e9900000nR",
414 | stm_2 = "e8800000nR", stmia_2 = "e8800000nR", stmfd_2 = "e8800000nR",
415 | stmda_2 = "e8000000nR", stmfa_2 = "e8000000nR",
416 | stmdb_2 = "e9000000nR", stmea_2 = "e9000000nR",
417 | stmib_2 = "e9800000nR", stmed_2 = "e9800000nR",
418 | pop_1 = "e8bd0000R", push_1 = "e92d0000R",
419 |
420 | -- Branch instructions.
421 | b_1 = "ea000000B",
422 | bl_1 = "eb000000B",
423 | blx_1 = "e12fff30C",
424 | bx_1 = "e12fff10M",
425 |
426 | -- Miscellaneous instructions.
427 | nop_0 = "e1a00000",
428 | mrs_1 = "e10f0000D",
429 | bkpt_1 = "e1200070K", -- v5T
430 | svc_1 = "ef000000T", swi_1 = "ef000000T",
431 | ud_0 = "e7f001f0",
432 |
433 | -- NYI: Advanced SIMD and VFP instructions.
434 |
435 | -- NYI instructions, since I have no need for them right now:
436 | -- swp, swpb, strex, ldrex, strexd, ldrexd, strexb, ldrexb, strexh, ldrexh
437 | -- msr, nopv6, yield, wfe, wfi, sev, dbg, bxj, smc, srs, rfe
438 | -- cps, setend, pli, pld, pldw, clrex, dsb, dmb, isb
439 | -- stc, ldc, mcr, mcr2, mrc, mrc2, mcrr, mcrr2, mrrc, mrrc2, cdp, cdp2
440 | }
441 |
442 | -- Add mnemonics for "s" variants.
443 | do
444 | local t = {}
445 | for k,v in pairs(map_op) do
446 | if sub(v, -1) == "s" then
447 | local v2 = sub(v, 1, 2)..char(byte(v, 3)+1)..sub(v, 4, -2)
448 | t[sub(k, 1, -3).."s"..sub(k, -2)] = v2
449 | end
450 | end
451 | for k,v in pairs(t) do
452 | map_op[k] = v
453 | end
454 | end
455 |
456 | ------------------------------------------------------------------------------
457 |
458 | local function parse_gpr(expr)
459 | local tname, ovreg = match(expr, "^([%w_]+):(r1?[0-9])$")
460 | local tp = map_type[tname or expr]
461 | if tp then
462 | local reg = ovreg or tp.reg
463 | if not reg then
464 | werror("type `"..(tname or expr).."' needs a register override")
465 | end
466 | expr = reg
467 | end
468 | local r = match(expr, "^r(1?[0-9])$")
469 | if r then
470 | r = tonumber(r)
471 | if r <= 15 then return r, tp end
472 | end
473 | werror("bad register name `"..expr.."'")
474 | end
475 |
476 | local function parse_gpr_pm(expr)
477 | local pm, expr2 = match(expr, "^([+-]?)(.*)$")
478 | return parse_gpr(expr2), (pm == "-")
479 | end
480 |
481 | local function parse_reglist(reglist)
482 | reglist = match(reglist, "^{%s*([^}]*)}$")
483 | if not reglist then werror("register list expected") end
484 | local rr = 0
485 | for p in gmatch(reglist..",", "%s*([^,]*),") do
486 | local rbit = 2^parse_gpr(gsub(p, "%s+$", ""))
487 | if ((rr - (rr % rbit)) / rbit) % 2 ~= 0 then
488 | werror("duplicate register `"..p.."'")
489 | end
490 | rr = rr + rbit
491 | end
492 | return rr
493 | end
494 |
495 | local function parse_imm(imm, bits, shift, scale, signed)
496 | imm = match(imm, "^#(.*)$")
497 | if not imm then werror("expected immediate operand") end
498 | local n = tonumber(imm)
499 | if n then
500 | if n % 2^scale == 0 then
501 | n = n / 2^scale
502 | if signed then
503 | if n >= 0 then
504 | if n < 2^(bits-1) then return n*2^shift end
505 | else
506 | if n >= -(2^(bits-1))-1 then return (n+2^bits)*2^shift end
507 | end
508 | else
509 | if n >= 0 and n <= 2^bits-1 then return n*2^shift end
510 | end
511 | end
512 | werror("out of range immediate `"..imm.."'")
513 | else
514 | waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm)
515 | return 0
516 | end
517 | end
518 |
519 | local function parse_imm12(imm)
520 | local n = tonumber(imm)
521 | if n then
522 | local m = n
523 | for i=0,-15,-1 do
524 | if m >= 0 and m <= 255 and n % 1 == 0 then return m + (i%16) * 256 end
525 | local t = m % 4
526 | m = (m - t) / 4 + t * 2^30
527 | end
528 | werror("out of range immediate `"..imm.."'")
529 | else
530 | waction("IMM12", 0, imm)
531 | return 0
532 | end
533 | end
534 |
535 | local function parse_imm16(imm)
536 | imm = match(imm, "^#(.*)$")
537 | if not imm then werror("expected immediate operand") end
538 | local n = tonumber(imm)
539 | if n then
540 | if n >= 0 and n <= 65535 and n % 1 == 0 then
541 | local t = n % 4096
542 | return (n - t) * 16 + t
543 | end
544 | werror("out of range immediate `"..imm.."'")
545 | else
546 | waction("IMM16", 32*16, imm)
547 | return 0
548 | end
549 | end
550 |
551 | local function parse_imm_load(imm, ext)
552 | local n = tonumber(imm)
553 | if n then
554 | if ext then
555 | if n >= -255 and n <= 255 then
556 | local up = 0x00800000
557 | if n < 0 then n = -n; up = 0 end
558 | return (n-(n%16))*16+(n%16) + up
559 | end
560 | else
561 | if n >= -4095 and n <= 4095 then
562 | if n >= 0 then return n+0x00800000 end
563 | return -n
564 | end
565 | end
566 | werror("out of range immediate `"..imm.."'")
567 | else
568 | waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12), imm)
569 | return 0
570 | end
571 | end
572 |
573 | local function parse_shift(shift, gprok)
574 | if shift == "rrx" then
575 | return 3 * 32
576 | else
577 | local s, s2 = match(shift, "^(%S+)%s*(.*)$")
578 | s = map_shift[s]
579 | if not s then werror("expected shift operand") end
580 | if sub(s2, 1, 1) == "#" then
581 | return parse_imm(s2, 5, 7, 0, false) + s * 32
582 | else
583 | if not gprok then werror("expected immediate shift operand") end
584 | return parse_gpr(s2) * 256 + s * 32 + 16
585 | end
586 | end
587 | end
588 |
589 | local function parse_label(label, def)
590 | local prefix = sub(label, 1, 2)
591 | -- =>label (pc label reference)
592 | if prefix == "=>" then
593 | return "PC", 0, sub(label, 3)
594 | end
595 | -- ->name (global label reference)
596 | if prefix == "->" then
597 | return "LG", map_global[sub(label, 3)]
598 | end
599 | if def then
600 | -- [1-9] (local label definition)
601 | if match(label, "^[1-9]$") then
602 | return "LG", 10+tonumber(label)
603 | end
604 | else
605 | -- [<>][1-9] (local label reference)
606 | local dir, lnum = match(label, "^([<>])([1-9])$")
607 | if dir then -- Fwd: 1-9, Bkwd: 11-19.
608 | return "LG", lnum + (dir == ">" and 0 or 10)
609 | end
610 | -- extern label (extern label reference)
611 | local extname = match(label, "^extern%s+(%S+)$")
612 | if extname then
613 | return "EXT", map_extern[extname]
614 | end
615 | end
616 | werror("bad label `"..label.."'")
617 | end
618 |
619 | local function parse_load(params, nparams, n, op)
620 | local oplo = op % 256
621 | local ext, ldrd = (oplo ~= 0), (oplo == 208)
622 | local d
623 | if (ldrd or oplo == 240) then
624 | d = ((op - (op % 4096)) / 4096) % 16
625 | if d % 2 ~= 0 then werror("odd destination register") end
626 | end
627 | local pn = params[n]
628 | local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$")
629 | local p2 = params[n+1]
630 | if not p1 then
631 | if not p2 then
632 | if match(pn, "^[<>=%-]") or match(pn, "^extern%s+") then
633 | local mode, n, s = parse_label(pn, false)
634 | waction("REL_"..mode, n + (ext and 0x1800 or 0x0800), s, 1)
635 | return op + 15 * 65536 + 0x01000000 + (ext and 0x00400000 or 0)
636 | end
637 | local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$")
638 | if reg and tailr ~= "" then
639 | local d, tp = parse_gpr(reg)
640 | if tp then
641 | waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12),
642 | format(tp.ctypefmt, tailr))
643 | return op + d * 65536 + 0x01000000 + (ext and 0x00400000 or 0)
644 | end
645 | end
646 | end
647 | werror("expected address operand")
648 | end
649 | if wb == "!" then op = op + 0x00200000 end
650 | if p2 then
651 | if wb == "!" then werror("bad use of '!'") end
652 | local p3 = params[n+2]
653 | op = op + parse_gpr(p1) * 65536
654 | local imm = match(p2, "^#(.*)$")
655 | if imm then
656 | local m = parse_imm_load(imm, ext)
657 | if p3 then werror("too many parameters") end
658 | op = op + m + (ext and 0x00400000 or 0)
659 | else
660 | local m, neg = parse_gpr_pm(p2)
661 | if ldrd and (m == d or m-1 == d) then werror("register conflict") end
662 | op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000)
663 | if p3 then op = op + parse_shift(p3) end
664 | end
665 | else
666 | local p1a, p2 = match(p1, "^([^,%s]*)%s*(.*)$")
667 | op = op + parse_gpr(p1a) * 65536 + 0x01000000
668 | if p2 ~= "" then
669 | local imm = match(p2, "^,%s*#(.*)$")
670 | if imm then
671 | local m = parse_imm_load(imm, ext)
672 | op = op + m + (ext and 0x00400000 or 0)
673 | else
674 | local p2a, p3 = match(p2, "^,%s*([^,%s]*)%s*,?%s*(.*)$")
675 | local m, neg = parse_gpr_pm(p2a)
676 | if ldrd and (m == d or m-1 == d) then werror("register conflict") end
677 | op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000)
678 | if p3 ~= "" then
679 | if ext then werror("too many parameters") end
680 | op = op + parse_shift(p3)
681 | end
682 | end
683 | else
684 | if wb == "!" then werror("bad use of '!'") end
685 | op = op + (ext and 0x00c00000 or 0x00800000)
686 | end
687 | end
688 | return op
689 | end
690 |
691 | ------------------------------------------------------------------------------
692 |
693 | -- Handle opcodes defined with template strings.
694 | map_op[".template__"] = function(params, template, nparams)
695 | if not params then return sub(template, 9) end
696 | local op = tonumber(sub(template, 1, 8), 16)
697 | local n = 1
698 |
699 | -- Limit number of section buffer positions used by a single dasm_put().
700 | -- A single opcode needs a maximum of 3 positions.
701 | if secpos+3 > maxsecpos then wflush() end
702 | local pos = wpos()
703 |
704 | -- Process each character.
705 | for p in gmatch(sub(template, 9), ".") do
706 | if p == "D" then
707 | op = op + parse_gpr(params[n]) * 4096; n = n + 1
708 | elseif p == "N" then
709 | op = op + parse_gpr(params[n]) * 65536; n = n + 1
710 | elseif p == "S" then
711 | op = op + parse_gpr(params[n]) * 256; n = n + 1
712 | elseif p == "M" then
713 | op = op + parse_gpr(params[n]); n = n + 1
714 | elseif p == "P" then
715 | local imm = match(params[n], "^#(.*)$")
716 | if imm then
717 | op = op + parse_imm12(imm) + 0x02000000
718 | else
719 | op = op + parse_gpr(params[n])
720 | end
721 | n = n + 1
722 | elseif p == "p" then
723 | op = op + parse_shift(params[n], true); n = n + 1
724 | elseif p == "L" then
725 | op = parse_load(params, nparams, n, op)
726 | elseif p == "B" then
727 | local mode, n, s = parse_label(params[n], false)
728 | waction("REL_"..mode, n, s, 1)
729 | elseif p == "C" then -- blx gpr vs. blx label.
730 | local p = params[n]
731 | if match(p, "^([%w_]+):(r1?[0-9])$") or match(p, "^r(1?[0-9])$") then
732 | op = op + parse_gpr(p)
733 | else
734 | if op < 0xe0000000 then werror("unconditional instruction") end
735 | local mode, n, s = parse_label(p, false)
736 | waction("REL_"..mode, n, s, 1)
737 | op = 0xfa000000
738 | end
739 | elseif p == "n" then
740 | local r, wb = match(params[n], "^([^!]*)(!?)$")
741 | op = op + parse_gpr(r) * 65536 + (wb == "!" and 0x00200000 or 0)
742 | n = n + 1
743 | elseif p == "R" then
744 | op = op + parse_reglist(params[n]); n = n + 1
745 | elseif p == "W" then
746 | op = op + parse_imm16(params[n]); n = n + 1
747 | elseif p == "v" then
748 | op = op + parse_imm(params[n], 5, 7, 0, false); n = n + 1
749 | elseif p == "w" then
750 | local imm = match(params[n], "^#(.*)$")
751 | if imm then
752 | op = op + parse_imm(params[n], 5, 7, 0, false); n = n + 1
753 | else
754 | op = op + parse_gpr(params[n]) * 256 + 16
755 | end
756 | elseif p == "X" then
757 | op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1
758 | elseif p == "K" then
759 | local imm = tonumber(match(params[n], "^#(.*)$")); n = n + 1
760 | if not imm or imm % 1 ~= 0 or imm < 0 or imm > 0xffff then
761 | werror("bad immediate operand")
762 | end
763 | local t = imm % 16
764 | op = op + (imm - t) * 16 + t
765 | elseif p == "T" then
766 | op = op + parse_imm(params[n], 24, 0, 0, false); n = n + 1
767 | elseif p == "s" then
768 | -- Ignored.
769 | else
770 | assert(false)
771 | end
772 | end
773 | wputpos(pos, op)
774 | end
775 |
776 | ------------------------------------------------------------------------------
777 |
778 | -- Pseudo-opcode to mark the position where the action list is to be emitted.
779 | map_op[".actionlist_1"] = function(params)
780 | if not params then return "cvar" end
781 | local name = params[1] -- No syntax check. You get to keep the pieces.
782 | wline(function(out) writeactions(out, name) end)
783 | end
784 |
785 | -- Pseudo-opcode to mark the position where the global enum is to be emitted.
786 | map_op[".globals_1"] = function(params)
787 | if not params then return "prefix" end
788 | local prefix = params[1] -- No syntax check. You get to keep the pieces.
789 | wline(function(out) writeglobals(out, prefix) end)
790 | end
791 |
792 | -- Pseudo-opcode to mark the position where the global names are to be emitted.
793 | map_op[".globalnames_1"] = function(params)
794 | if not params then return "cvar" end
795 | local name = params[1] -- No syntax check. You get to keep the pieces.
796 | wline(function(out) writeglobalnames(out, name) end)
797 | end
798 |
799 | -- Pseudo-opcode to mark the position where the extern names are to be emitted.
800 | map_op[".externnames_1"] = function(params)
801 | if not params then return "cvar" end
802 | local name = params[1] -- No syntax check. You get to keep the pieces.
803 | wline(function(out) writeexternnames(out, name) end)
804 | end
805 |
806 | ------------------------------------------------------------------------------
807 |
808 | -- Label pseudo-opcode (converted from trailing colon form).
809 | map_op[".label_1"] = function(params)
810 | if not params then return "[1-9] | ->global | =>pcexpr" end
811 | if secpos+1 > maxsecpos then wflush() end
812 | local mode, n, s = parse_label(params[1], true)
813 | if mode == "EXT" then werror("bad label definition") end
814 | waction("LABEL_"..mode, n, s, 1)
815 | end
816 |
817 | ------------------------------------------------------------------------------
818 |
819 | -- Pseudo-opcodes for data storage.
820 | map_op[".long_*"] = function(params)
821 | if not params then return "imm..." end
822 | for _,p in ipairs(params) do
823 | local n = tonumber(p)
824 | if not n then werror("bad immediate `"..p.."'") end
825 | if n < 0 then n = n + 2^32 end
826 | wputw(n)
827 | if secpos+2 > maxsecpos then wflush() end
828 | end
829 | end
830 |
831 | -- Alignment pseudo-opcode.
832 | map_op[".align_1"] = function(params)
833 | if not params then return "numpow2" end
834 | if secpos+1 > maxsecpos then wflush() end
835 | local align = tonumber(params[1])
836 | if align then
837 | local x = align
838 | -- Must be a power of 2 in the range (2 ... 256).
839 | for i=1,8 do
840 | x = x / 2
841 | if x == 1 then
842 | waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1.
843 | return
844 | end
845 | end
846 | end
847 | werror("bad alignment")
848 | end
849 |
850 | ------------------------------------------------------------------------------
851 |
852 | -- Pseudo-opcode for (primitive) type definitions (map to C types).
853 | map_op[".type_3"] = function(params, nparams)
854 | if not params then
855 | return nparams == 2 and "name, ctype" or "name, ctype, reg"
856 | end
857 | local name, ctype, reg = params[1], params[2], params[3]
858 | if not match(name, "^[%a_][%w_]*$") then
859 | werror("bad type name `"..name.."'")
860 | end
861 | local tp = map_type[name]
862 | if tp then
863 | werror("duplicate type `"..name.."'")
864 | end
865 | -- Add #type to defines. A bit unclean to put it in map_archdef.
866 | map_archdef["#"..name] = "sizeof("..ctype..")"
867 | -- Add new type and emit shortcut define.
868 | local num = ctypenum + 1
869 | map_type[name] = {
870 | ctype = ctype,
871 | ctypefmt = format("Dt%X(%%s)", num),
872 | reg = reg,
873 | }
874 | wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
875 | ctypenum = num
876 | end
877 | map_op[".type_2"] = map_op[".type_3"]
878 |
879 | -- Dump type definitions.
880 | local function dumptypes(out, lvl)
881 | local t = {}
882 | for name in pairs(map_type) do t[#t+1] = name end
883 | sort(t)
884 | out:write("Type definitions:\n")
885 | for _,name in ipairs(t) do
886 | local tp = map_type[name]
887 | local reg = tp.reg or ""
888 | out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
889 | end
890 | out:write("\n")
891 | end
892 |
893 | ------------------------------------------------------------------------------
894 |
895 | -- Set the current section.
896 | function _M.section(num)
897 | waction("SECTION", num)
898 | wflush(true) -- SECTION is a terminal action.
899 | end
900 |
901 | ------------------------------------------------------------------------------
902 |
903 | -- Dump architecture description.
904 | function _M.dumparch(out)
905 | out:write(format("DynASM %s version %s, released %s\n\n",
906 | _info.arch, _info.version, _info.release))
907 | dumpactions(out)
908 | end
909 |
910 | -- Dump all user defined elements.
911 | function _M.dumpdef(out, lvl)
912 | dumptypes(out, lvl)
913 | dumpglobals(out, lvl)
914 | dumpexterns(out, lvl)
915 | end
916 |
917 | ------------------------------------------------------------------------------
918 |
919 | -- Pass callbacks from/to the DynASM core.
920 | function _M.passcb(wl, we, wf, ww)
921 | wline, werror, wfatal, wwarn = wl, we, wf, ww
922 | return wflush
923 | end
924 |
925 | -- Setup the arch-specific module.
926 | function _M.setup(arch, opt)
927 | g_arch, g_opt = arch, opt
928 | end
929 |
930 | -- Merge the core maps and the arch-specific maps.
931 | function _M.mergemaps(map_coreop, map_def)
932 | setmetatable(map_op, { __index = function(t, k)
933 | local v = map_coreop[k]
934 | if v then return v end
935 | local cc = sub(k, -4, -3)
936 | local cv = map_cond[cc]
937 | if cv then
938 | local v = rawget(t, sub(k, 1, -5)..sub(k, -2))
939 | if type(v) == "string" then return format("%x%s", cv, sub(v, 2)) end
940 | end
941 | end })
942 | setmetatable(map_def, { __index = map_archdef })
943 | return map_op, map_def
944 | end
945 |
946 | return _M
947 |
948 | ------------------------------------------------------------------------------
949 |
950 |
--------------------------------------------------------------------------------
/third_party/dynasm/dasm_mips.h:
--------------------------------------------------------------------------------
1 | /*
2 | ** DynASM MIPS encoding engine.
3 | ** Copyright (C) 2005-2012 Mike Pall. All rights reserved.
4 | ** Released under the MIT license. See dynasm.lua for full copyright notice.
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #define DASM_ARCH "mips"
13 |
14 | #ifndef DASM_EXTERN
15 | #define DASM_EXTERN(a,b,c,d) 0
16 | #endif
17 |
18 | /* Action definitions. */
19 | enum {
20 | DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
21 | /* The following actions need a buffer position. */
22 | DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
23 | /* The following actions also have an argument. */
24 | DASM_REL_PC, DASM_LABEL_PC, DASM_IMM,
25 | DASM__MAX
26 | };
27 |
28 | /* Maximum number of section buffer positions for a single dasm_put() call. */
29 | #define DASM_MAXSECPOS 25
30 |
31 | /* DynASM encoder status codes. Action list offset or number are or'ed in. */
32 | #define DASM_S_OK 0x00000000
33 | #define DASM_S_NOMEM 0x01000000
34 | #define DASM_S_PHASE 0x02000000
35 | #define DASM_S_MATCH_SEC 0x03000000
36 | #define DASM_S_RANGE_I 0x11000000
37 | #define DASM_S_RANGE_SEC 0x12000000
38 | #define DASM_S_RANGE_LG 0x13000000
39 | #define DASM_S_RANGE_PC 0x14000000
40 | #define DASM_S_RANGE_REL 0x15000000
41 | #define DASM_S_UNDEF_LG 0x21000000
42 | #define DASM_S_UNDEF_PC 0x22000000
43 |
44 | /* Macros to convert positions (8 bit section + 24 bit index). */
45 | #define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
46 | #define DASM_POS2BIAS(pos) ((pos)&0xff000000)
47 | #define DASM_SEC2POS(sec) ((sec)<<24)
48 | #define DASM_POS2SEC(pos) ((pos)>>24)
49 | #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
50 |
51 | /* Action list type. */
52 | typedef const unsigned int *dasm_ActList;
53 |
54 | /* Per-section structure. */
55 | typedef struct dasm_Section {
56 | int *rbuf; /* Biased buffer pointer (negative section bias). */
57 | int *buf; /* True buffer pointer. */
58 | size_t bsize; /* Buffer size in bytes. */
59 | int pos; /* Biased buffer position. */
60 | int epos; /* End of biased buffer position - max single put. */
61 | int ofs; /* Byte offset into section. */
62 | } dasm_Section;
63 |
64 | /* Core structure holding the DynASM encoding state. */
65 | struct dasm_State {
66 | size_t psize; /* Allocated size of this structure. */
67 | dasm_ActList actionlist; /* Current actionlist pointer. */
68 | int *lglabels; /* Local/global chain/pos ptrs. */
69 | size_t lgsize;
70 | int *pclabels; /* PC label chains/pos ptrs. */
71 | size_t pcsize;
72 | void **globals; /* Array of globals (bias -10). */
73 | dasm_Section *section; /* Pointer to active section. */
74 | size_t codesize; /* Total size of all code sections. */
75 | int maxsection; /* 0 <= sectionidx < maxsection. */
76 | int status; /* Status code. */
77 | dasm_Section sections[1]; /* All sections. Alloc-extended. */
78 | };
79 |
80 | /* The size of the core structure depends on the max. number of sections. */
81 | #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
82 |
83 |
84 | /* Initialize DynASM state. */
85 | void dasm_init(Dst_DECL, int maxsection)
86 | {
87 | dasm_State *D;
88 | size_t psz = 0;
89 | int i;
90 | Dst_REF = NULL;
91 | DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
92 | D = Dst_REF;
93 | D->psize = psz;
94 | D->lglabels = NULL;
95 | D->lgsize = 0;
96 | D->pclabels = NULL;
97 | D->pcsize = 0;
98 | D->globals = NULL;
99 | D->maxsection = maxsection;
100 | for (i = 0; i < maxsection; i++) {
101 | D->sections[i].buf = NULL; /* Need this for pass3. */
102 | D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
103 | D->sections[i].bsize = 0;
104 | D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
105 | }
106 | }
107 |
108 | /* Free DynASM state. */
109 | void dasm_free(Dst_DECL)
110 | {
111 | dasm_State *D = Dst_REF;
112 | int i;
113 | for (i = 0; i < D->maxsection; i++)
114 | if (D->sections[i].buf)
115 | DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
116 | if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
117 | if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
118 | DASM_M_FREE(Dst, D, D->psize);
119 | }
120 |
121 | /* Setup global label array. Must be called before dasm_setup(). */
122 | void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
123 | {
124 | dasm_State *D = Dst_REF;
125 | D->globals = gl - 10; /* Negative bias to compensate for locals. */
126 | DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
127 | }
128 |
129 | /* Grow PC label array. Can be called after dasm_setup(), too. */
130 | void dasm_growpc(Dst_DECL, unsigned int maxpc)
131 | {
132 | dasm_State *D = Dst_REF;
133 | size_t osz = D->pcsize;
134 | DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
135 | memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
136 | }
137 |
138 | /* Setup encoder. */
139 | void dasm_setup(Dst_DECL, const void *actionlist)
140 | {
141 | dasm_State *D = Dst_REF;
142 | int i;
143 | D->actionlist = (dasm_ActList)actionlist;
144 | D->status = DASM_S_OK;
145 | D->section = &D->sections[0];
146 | memset((void *)D->lglabels, 0, D->lgsize);
147 | if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
148 | for (i = 0; i < D->maxsection; i++) {
149 | D->sections[i].pos = DASM_SEC2POS(i);
150 | D->sections[i].ofs = 0;
151 | }
152 | }
153 |
154 |
155 | #ifdef DASM_CHECKS
156 | #define CK(x, st) \
157 | do { if (!(x)) { \
158 | D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
159 | #define CKPL(kind, st) \
160 | do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
161 | D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
162 | #else
163 | #define CK(x, st) ((void)0)
164 | #define CKPL(kind, st) ((void)0)
165 | #endif
166 |
167 | /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
168 | void dasm_put(Dst_DECL, int start, ...)
169 | {
170 | va_list ap;
171 | dasm_State *D = Dst_REF;
172 | dasm_ActList p = D->actionlist + start;
173 | dasm_Section *sec = D->section;
174 | int pos = sec->pos, ofs = sec->ofs;
175 | int *b;
176 |
177 | if (pos >= sec->epos) {
178 | DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
179 | sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
180 | sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
181 | sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
182 | }
183 |
184 | b = sec->rbuf;
185 | b[pos++] = start;
186 |
187 | va_start(ap, start);
188 | while (1) {
189 | unsigned int ins = *p++;
190 | unsigned int action = (ins >> 16) - 0xff00;
191 | if (action >= DASM__MAX) {
192 | ofs += 4;
193 | } else {
194 | int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
195 | switch (action) {
196 | case DASM_STOP: goto stop;
197 | case DASM_SECTION:
198 | n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
199 | D->section = &D->sections[n]; goto stop;
200 | case DASM_ESC: p++; ofs += 4; break;
201 | case DASM_REL_EXT: break;
202 | case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
203 | case DASM_REL_LG:
204 | n = (ins & 2047) - 10; pl = D->lglabels + n;
205 | if (n >= 0) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */
206 | pl += 10; n = *pl;
207 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
208 | goto linkrel;
209 | case DASM_REL_PC:
210 | pl = D->pclabels + n; CKPL(pc, PC);
211 | putrel:
212 | n = *pl;
213 | if (n < 0) { /* Label exists. Get label pos and store it. */
214 | b[pos] = -n;
215 | } else {
216 | linkrel:
217 | b[pos] = n; /* Else link to rel chain, anchored at label. */
218 | *pl = pos;
219 | }
220 | pos++;
221 | break;
222 | case DASM_LABEL_LG:
223 | pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
224 | case DASM_LABEL_PC:
225 | pl = D->pclabels + n; CKPL(pc, PC);
226 | putlabel:
227 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
228 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
229 | }
230 | *pl = -pos; /* Label exists now. */
231 | b[pos++] = ofs; /* Store pass1 offset estimate. */
232 | break;
233 | case DASM_IMM:
234 | #ifdef DASM_CHECKS
235 | CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
236 | #endif
237 | n >>= ((ins>>10)&31);
238 | #ifdef DASM_CHECKS
239 | if (ins & 0x8000)
240 | CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
241 | else
242 | CK((n>>((ins>>5)&31)) == 0, RANGE_I);
243 | #endif
244 | b[pos++] = n;
245 | break;
246 | }
247 | }
248 | }
249 | stop:
250 | va_end(ap);
251 | sec->pos = pos;
252 | sec->ofs = ofs;
253 | }
254 | #undef CK
255 |
256 | /* Pass 2: Link sections, shrink aligns, fix label offsets. */
257 | int dasm_link(Dst_DECL, size_t *szp)
258 | {
259 | dasm_State *D = Dst_REF;
260 | int secnum;
261 | int ofs = 0;
262 |
263 | #ifdef DASM_CHECKS
264 | *szp = 0;
265 | if (D->status != DASM_S_OK) return D->status;
266 | {
267 | int pc;
268 | for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
269 | if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
270 | }
271 | #endif
272 |
273 | { /* Handle globals not defined in this translation unit. */
274 | int idx;
275 | for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
276 | int n = D->lglabels[idx];
277 | /* Undefined label: Collapse rel chain and replace with marker (< 0). */
278 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
279 | }
280 | }
281 |
282 | /* Combine all code sections. No support for data sections (yet). */
283 | for (secnum = 0; secnum < D->maxsection; secnum++) {
284 | dasm_Section *sec = D->sections + secnum;
285 | int *b = sec->rbuf;
286 | int pos = DASM_SEC2POS(secnum);
287 | int lastpos = sec->pos;
288 |
289 | while (pos != lastpos) {
290 | dasm_ActList p = D->actionlist + b[pos++];
291 | while (1) {
292 | unsigned int ins = *p++;
293 | unsigned int action = (ins >> 16) - 0xff00;
294 | switch (action) {
295 | case DASM_STOP: case DASM_SECTION: goto stop;
296 | case DASM_ESC: p++; break;
297 | case DASM_REL_EXT: break;
298 | case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
299 | case DASM_REL_LG: case DASM_REL_PC: pos++; break;
300 | case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
301 | case DASM_IMM: pos++; break;
302 | }
303 | }
304 | stop: (void)0;
305 | }
306 | ofs += sec->ofs; /* Next section starts right after current section. */
307 | }
308 |
309 | D->codesize = ofs; /* Total size of all code sections */
310 | *szp = ofs;
311 | return DASM_S_OK;
312 | }
313 |
314 | #ifdef DASM_CHECKS
315 | #define CK(x, st) \
316 | do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
317 | #else
318 | #define CK(x, st) ((void)0)
319 | #endif
320 |
321 | /* Pass 3: Encode sections. */
322 | int dasm_encode(Dst_DECL, void *buffer)
323 | {
324 | dasm_State *D = Dst_REF;
325 | char *base = (char *)buffer;
326 | unsigned int *cp = (unsigned int *)buffer;
327 | int secnum;
328 |
329 | /* Encode all code sections. No support for data sections (yet). */
330 | for (secnum = 0; secnum < D->maxsection; secnum++) {
331 | dasm_Section *sec = D->sections + secnum;
332 | int *b = sec->buf;
333 | int *endb = sec->rbuf + sec->pos;
334 |
335 | while (b != endb) {
336 | dasm_ActList p = D->actionlist + *b++;
337 | while (1) {
338 | unsigned int ins = *p++;
339 | unsigned int action = (ins >> 16) - 0xff00;
340 | int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
341 | switch (action) {
342 | case DASM_STOP: case DASM_SECTION: goto stop;
343 | case DASM_ESC: *cp++ = *p++; break;
344 | case DASM_REL_EXT:
345 | n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1);
346 | goto patchrel;
347 | case DASM_ALIGN:
348 | ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000;
349 | break;
350 | case DASM_REL_LG:
351 | CK(n >= 0, UNDEF_LG);
352 | case DASM_REL_PC:
353 | CK(n >= 0, UNDEF_PC);
354 | n = *DASM_POS2PTR(D, n);
355 | if (ins & 2048)
356 | n = n - (int)((char *)cp - base);
357 | else
358 | n = (n + (int)base) & 0x0fffffff;
359 | patchrel:
360 | CK((n & 3) == 0 &&
361 | ((n + ((ins & 2048) ? 0x00020000 : 0)) >>
362 | ((ins & 2048) ? 18 : 28)) == 0, RANGE_REL);
363 | cp[-1] |= ((n>>2) & ((ins & 2048) ? 0x0000ffff: 0x03ffffff));
364 | break;
365 | case DASM_LABEL_LG:
366 | ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
367 | break;
368 | case DASM_LABEL_PC: break;
369 | case DASM_IMM:
370 | cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
371 | break;
372 | default: *cp++ = ins; break;
373 | }
374 | }
375 | stop: (void)0;
376 | }
377 | }
378 |
379 | if (base + D->codesize != (char *)cp) /* Check for phase errors. */
380 | return DASM_S_PHASE;
381 | return DASM_S_OK;
382 | }
383 | #undef CK
384 |
385 | /* Get PC label offset. */
386 | int dasm_getpclabel(Dst_DECL, unsigned int pc)
387 | {
388 | dasm_State *D = Dst_REF;
389 | if (pc*sizeof(int) < D->pcsize) {
390 | int pos = D->pclabels[pc];
391 | if (pos < 0) return *DASM_POS2PTR(D, -pos);
392 | if (pos > 0) return -1; /* Undefined. */
393 | }
394 | return -2; /* Unused or out of range. */
395 | }
396 |
397 | #ifdef DASM_CHECKS
398 | /* Optional sanity checker to call between isolated encoding steps. */
399 | int dasm_checkstep(Dst_DECL, int secmatch)
400 | {
401 | dasm_State *D = Dst_REF;
402 | if (D->status == DASM_S_OK) {
403 | int i;
404 | for (i = 1; i <= 9; i++) {
405 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
406 | D->lglabels[i] = 0;
407 | }
408 | }
409 | if (D->status == DASM_S_OK && secmatch >= 0 &&
410 | D->section != &D->sections[secmatch])
411 | D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
412 | return D->status;
413 | }
414 | #endif
415 |
416 |
--------------------------------------------------------------------------------
/third_party/dynasm/dasm_mips.lua:
--------------------------------------------------------------------------------
1 | ------------------------------------------------------------------------------
2 | -- DynASM MIPS module.
3 | --
4 | -- Copyright (C) 2005-2012 Mike Pall. All rights reserved.
5 | -- See dynasm.lua for full copyright notice.
6 | ------------------------------------------------------------------------------
7 |
8 | -- Module information:
9 | local _info = {
10 | arch = "mips",
11 | description = "DynASM MIPS module",
12 | version = "1.3.0",
13 | vernum = 10300,
14 | release = "2012-01-23",
15 | author = "Mike Pall",
16 | license = "MIT",
17 | }
18 |
19 | -- Exported glue functions for the arch-specific module.
20 | local _M = { _info = _info }
21 |
22 | -- Cache library functions.
23 | local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
24 | local assert, setmetatable = assert, setmetatable
25 | local _s = string
26 | local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
27 | local match, gmatch = _s.match, _s.gmatch
28 | local concat, sort = table.concat, table.sort
29 |
30 | -- Inherited tables and callbacks.
31 | local g_opt, g_arch
32 | local wline, werror, wfatal, wwarn
33 |
34 | -- Action name list.
35 | -- CHECK: Keep this in sync with the C code!
36 | local action_names = {
37 | "STOP", "SECTION", "ESC", "REL_EXT",
38 | "ALIGN", "REL_LG", "LABEL_LG",
39 | "REL_PC", "LABEL_PC", "IMM",
40 | }
41 |
42 | -- Maximum number of section buffer positions for dasm_put().
43 | -- CHECK: Keep this in sync with the C code!
44 | local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
45 |
46 | -- Action name -> action number.
47 | local map_action = {}
48 | for n,name in ipairs(action_names) do
49 | map_action[name] = n-1
50 | end
51 |
52 | -- Action list buffer.
53 | local actlist = {}
54 |
55 | -- Argument list for next dasm_put(). Start with offset 0 into action list.
56 | local actargs = { 0 }
57 |
58 | -- Current number of section buffer positions for dasm_put().
59 | local secpos = 1
60 |
61 | ------------------------------------------------------------------------------
62 |
63 | -- Return 8 digit hex number.
64 | local function tohex(x)
65 | return sub(format("%08x", x), -8) -- Avoid 64 bit portability problem in Lua.
66 | end
67 |
68 | -- Dump action names and numbers.
69 | local function dumpactions(out)
70 | out:write("DynASM encoding engine action codes:\n")
71 | for n,name in ipairs(action_names) do
72 | local num = map_action[name]
73 | out:write(format(" %-10s %02X %d\n", name, num, num))
74 | end
75 | out:write("\n")
76 | end
77 |
78 | -- Write action list buffer as a huge static C array.
79 | local function writeactions(out, name)
80 | local nn = #actlist
81 | if nn == 0 then nn = 1; actlist[0] = map_action.STOP end
82 | out:write("static const unsigned int ", name, "[", nn, "] = {\n")
83 | for i = 1,nn-1 do
84 | assert(out:write("0x", tohex(actlist[i]), ",\n"))
85 | end
86 | assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n"))
87 | end
88 |
89 | ------------------------------------------------------------------------------
90 |
91 | -- Add word to action list.
92 | local function wputxw(n)
93 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
94 | actlist[#actlist+1] = n
95 | end
96 |
97 | -- Add action to list with optional arg. Advance buffer pos, too.
98 | local function waction(action, val, a, num)
99 | local w = assert(map_action[action], "bad action name `"..action.."'")
100 | wputxw(0xff000000 + w * 0x10000 + (val or 0))
101 | if a then actargs[#actargs+1] = a end
102 | if a or num then secpos = secpos + (num or 1) end
103 | end
104 |
105 | -- Flush action list (intervening C code or buffer pos overflow).
106 | local function wflush(term)
107 | if #actlist == actargs[1] then return end -- Nothing to flush.
108 | if not term then waction("STOP") end -- Terminate action list.
109 | wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true)
110 | actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
111 | secpos = 1 -- The actionlist offset occupies a buffer position, too.
112 | end
113 |
114 | -- Put escaped word.
115 | local function wputw(n)
116 | if n >= 0xff000000 then waction("ESC") end
117 | wputxw(n)
118 | end
119 |
120 | -- Reserve position for word.
121 | local function wpos()
122 | local pos = #actlist+1
123 | actlist[pos] = ""
124 | return pos
125 | end
126 |
127 | -- Store word to reserved position.
128 | local function wputpos(pos, n)
129 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
130 | actlist[pos] = n
131 | end
132 |
133 | ------------------------------------------------------------------------------
134 |
135 | -- Global label name -> global label number. With auto assignment on 1st use.
136 | local next_global = 20
137 | local map_global = setmetatable({}, { __index = function(t, name)
138 | if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
139 | local n = next_global
140 | if n > 2047 then werror("too many global labels") end
141 | next_global = n + 1
142 | t[name] = n
143 | return n
144 | end})
145 |
146 | -- Dump global labels.
147 | local function dumpglobals(out, lvl)
148 | local t = {}
149 | for name, n in pairs(map_global) do t[n] = name end
150 | out:write("Global labels:\n")
151 | for i=20,next_global-1 do
152 | out:write(format(" %s\n", t[i]))
153 | end
154 | out:write("\n")
155 | end
156 |
157 | -- Write global label enum.
158 | local function writeglobals(out, prefix)
159 | local t = {}
160 | for name, n in pairs(map_global) do t[n] = name end
161 | out:write("enum {\n")
162 | for i=20,next_global-1 do
163 | out:write(" ", prefix, t[i], ",\n")
164 | end
165 | out:write(" ", prefix, "_MAX\n};\n")
166 | end
167 |
168 | -- Write global label names.
169 | local function writeglobalnames(out, name)
170 | local t = {}
171 | for name, n in pairs(map_global) do t[n] = name end
172 | out:write("static const char *const ", name, "[] = {\n")
173 | for i=20,next_global-1 do
174 | out:write(" \"", t[i], "\",\n")
175 | end
176 | out:write(" (const char *)0\n};\n")
177 | end
178 |
179 | ------------------------------------------------------------------------------
180 |
181 | -- Extern label name -> extern label number. With auto assignment on 1st use.
182 | local next_extern = 0
183 | local map_extern_ = {}
184 | local map_extern = setmetatable({}, { __index = function(t, name)
185 | -- No restrictions on the name for now.
186 | local n = next_extern
187 | if n > 2047 then werror("too many extern labels") end
188 | next_extern = n + 1
189 | t[name] = n
190 | map_extern_[n] = name
191 | return n
192 | end})
193 |
194 | -- Dump extern labels.
195 | local function dumpexterns(out, lvl)
196 | out:write("Extern labels:\n")
197 | for i=0,next_extern-1 do
198 | out:write(format(" %s\n", map_extern_[i]))
199 | end
200 | out:write("\n")
201 | end
202 |
203 | -- Write extern label names.
204 | local function writeexternnames(out, name)
205 | out:write("static const char *const ", name, "[] = {\n")
206 | for i=0,next_extern-1 do
207 | out:write(" \"", map_extern_[i], "\",\n")
208 | end
209 | out:write(" (const char *)0\n};\n")
210 | end
211 |
212 | ------------------------------------------------------------------------------
213 |
214 | -- Arch-specific maps.
215 | local map_archdef = { sp="r29", ra="r31" } -- Ext. register name -> int. name.
216 |
217 | local map_type = {} -- Type name -> { ctype, reg }
218 | local ctypenum = 0 -- Type number (for Dt... macros).
219 |
220 | -- Reverse defines for registers.
221 | function _M.revdef(s)
222 | if s == "r29" then return "sp"
223 | elseif s == "r31" then return "ra" end
224 | return s
225 | end
226 |
227 | ------------------------------------------------------------------------------
228 |
229 | -- Template strings for MIPS instructions.
230 | local map_op = {
231 | -- First-level opcodes.
232 | j_1 = "08000000J",
233 | jal_1 = "0c000000J",
234 | b_1 = "10000000B",
235 | beqz_2 = "10000000SB",
236 | beq_3 = "10000000STB",
237 | bnez_2 = "14000000SB",
238 | bne_3 = "14000000STB",
239 | blez_2 = "18000000SB",
240 | bgtz_2 = "1c000000SB",
241 | addi_3 = "20000000TSI",
242 | li_2 = "24000000TI",
243 | addiu_3 = "24000000TSI",
244 | slti_3 = "28000000TSI",
245 | sltiu_3 = "2c000000TSI",
246 | andi_3 = "30000000TSU",
247 | lu_2 = "34000000TU",
248 | ori_3 = "34000000TSU",
249 | xori_3 = "38000000TSU",
250 | lui_2 = "3c000000TU",
251 | beqzl_2 = "50000000SB",
252 | beql_3 = "50000000STB",
253 | bnezl_2 = "54000000SB",
254 | bnel_3 = "54000000STB",
255 | blezl_2 = "58000000SB",
256 | bgtzl_2 = "5c000000SB",
257 | lb_2 = "80000000TO",
258 | lh_2 = "84000000TO",
259 | lwl_2 = "88000000TO",
260 | lw_2 = "8c000000TO",
261 | lbu_2 = "90000000TO",
262 | lhu_2 = "94000000TO",
263 | lwr_2 = "98000000TO",
264 | sb_2 = "a0000000TO",
265 | sh_2 = "a4000000TO",
266 | swl_2 = "a8000000TO",
267 | sw_2 = "ac000000TO",
268 | swr_2 = "b8000000TO",
269 | cache_2 = "bc000000NO",
270 | ll_2 = "c0000000TO",
271 | lwc1_2 = "c4000000HO",
272 | pref_2 = "cc000000NO",
273 | ldc1_2 = "d4000000HO",
274 | sc_2 = "e0000000TO",
275 | swc1_2 = "e4000000HO",
276 | sdc1_2 = "f4000000HO",
277 |
278 | -- Opcode SPECIAL.
279 | nop_0 = "00000000",
280 | sll_3 = "00000000DTA",
281 | movf_2 = "00000001DS",
282 | movf_3 = "00000001DSC",
283 | movt_2 = "00010001DS",
284 | movt_3 = "00010001DSC",
285 | srl_3 = "00000002DTA",
286 | rotr_3 = "00200002DTA",
287 | sra_3 = "00000003DTA",
288 | sllv_3 = "00000004DTS",
289 | srlv_3 = "00000006DTS",
290 | rotrv_3 = "00000046DTS",
291 | srav_3 = "00000007DTS",
292 | jr_1 = "00000008S",
293 | jalr_1 = "0000f809S",
294 | jalr_2 = "00000009DS",
295 | movz_3 = "0000000aDST",
296 | movn_3 = "0000000bDST",
297 | syscall_0 = "0000000c",
298 | syscall_1 = "0000000cY",
299 | break_0 = "0000000d",
300 | break_1 = "0000000dY",
301 | sync_0 = "0000000f",
302 | mfhi_1 = "00000010D",
303 | mthi_1 = "00000011S",
304 | mflo_1 = "00000012D",
305 | mtlo_1 = "00000013S",
306 | mult_2 = "00000018ST",
307 | multu_2 = "00000019ST",
308 | div_2 = "0000001aST",
309 | divu_2 = "0000001bST",
310 | add_3 = "00000020DST",
311 | move_2 = "00000021DS",
312 | addu_3 = "00000021DST",
313 | sub_3 = "00000022DST",
314 | negu_2 = "00000023DT",
315 | subu_3 = "00000023DST",
316 | and_3 = "00000024DST",
317 | or_3 = "00000025DST",
318 | xor_3 = "00000026DST",
319 | not_2 = "00000027DS",
320 | nor_3 = "00000027DST",
321 | slt_3 = "0000002aDST",
322 | sltu_3 = "0000002bDST",
323 | tge_2 = "00000030ST",
324 | tge_3 = "00000030STZ",
325 | tgeu_2 = "00000031ST",
326 | tgeu_3 = "00000031STZ",
327 | tlt_2 = "00000032ST",
328 | tlt_3 = "00000032STZ",
329 | tltu_2 = "00000033ST",
330 | tltu_3 = "00000033STZ",
331 | teq_2 = "00000034ST",
332 | teq_3 = "00000034STZ",
333 | tne_2 = "00000036ST",
334 | tne_3 = "00000036STZ",
335 |
336 | -- Opcode REGIMM.
337 | bltz_2 = "04000000SB",
338 | bgez_2 = "04010000SB",
339 | bltzl_2 = "04020000SB",
340 | bgezl_2 = "04030000SB",
341 | tgei_2 = "04080000SI",
342 | tgeiu_2 = "04090000SI",
343 | tlti_2 = "040a0000SI",
344 | tltiu_2 = "040b0000SI",
345 | teqi_2 = "040c0000SI",
346 | tnei_2 = "040e0000SI",
347 | bltzal_2 = "04100000SB",
348 | bal_1 = "04110000B",
349 | bgezal_2 = "04110000SB",
350 | bltzall_2 = "04120000SB",
351 | bgezall_2 = "04130000SB",
352 | synci_1 = "041f0000O",
353 |
354 | -- Opcode SPECIAL2.
355 | madd_2 = "70000000ST",
356 | maddu_2 = "70000001ST",
357 | mul_3 = "70000002DST",
358 | msub_2 = "70000004ST",
359 | msubu_2 = "70000005ST",
360 | clz_2 = "70000020DS=",
361 | clo_2 = "70000021DS=",
362 | sdbbp_0 = "7000003f",
363 | sdbbp_1 = "7000003fY",
364 |
365 | -- Opcode SPECIAL3.
366 | ext_4 = "7c000000TSAM", -- Note: last arg is msbd = size-1
367 | ins_4 = "7c000004TSAM", -- Note: last arg is msb = pos+size-1
368 | wsbh_2 = "7c0000a0DT",
369 | seb_2 = "7c000420DT",
370 | seh_2 = "7c000620DT",
371 | rdhwr_2 = "7c00003bTD",
372 |
373 | -- Opcode COP0.
374 | mfc0_2 = "40000000TD",
375 | mfc0_3 = "40000000TDW",
376 | mtc0_2 = "40800000TD",
377 | mtc0_3 = "40800000TDW",
378 | rdpgpr_2 = "41400000DT",
379 | di_0 = "41606000",
380 | di_1 = "41606000T",
381 | ei_0 = "41606020",
382 | ei_1 = "41606020T",
383 | wrpgpr_2 = "41c00000DT",
384 | tlbr_0 = "42000001",
385 | tlbwi_0 = "42000002",
386 | tlbwr_0 = "42000006",
387 | tlbp_0 = "42000008",
388 | eret_0 = "42000018",
389 | deret_0 = "4200001f",
390 | wait_0 = "42000020",
391 |
392 | -- Opcode COP1.
393 | mfc1_2 = "44000000TG",
394 | cfc1_2 = "44400000TG",
395 | mfhc1_2 = "44600000TG",
396 | mtc1_2 = "44800000TG",
397 | ctc1_2 = "44c00000TG",
398 | mthc1_2 = "44e00000TG",
399 |
400 | bc1f_1 = "45000000B",
401 | bc1f_2 = "45000000CB",
402 | bc1t_1 = "45010000B",
403 | bc1t_2 = "45010000CB",
404 | bc1fl_1 = "45020000B",
405 | bc1fl_2 = "45020000CB",
406 | bc1tl_1 = "45030000B",
407 | bc1tl_2 = "45030000CB",
408 |
409 | ["add.s_3"] = "46000000FGH",
410 | ["sub.s_3"] = "46000001FGH",
411 | ["mul.s_3"] = "46000002FGH",
412 | ["div.s_3"] = "46000003FGH",
413 | ["sqrt.s_2"] = "46000004FG",
414 | ["abs.s_2"] = "46000005FG",
415 | ["mov.s_2"] = "46000006FG",
416 | ["neg.s_2"] = "46000007FG",
417 | ["round.l.s_2"] = "46000008FG",
418 | ["trunc.l.s_2"] = "46000009FG",
419 | ["ceil.l.s_2"] = "4600000aFG",
420 | ["floor.l.s_2"] = "4600000bFG",
421 | ["round.w.s_2"] = "4600000cFG",
422 | ["trunc.w.s_2"] = "4600000dFG",
423 | ["ceil.w.s_2"] = "4600000eFG",
424 | ["floor.w.s_2"] = "4600000fFG",
425 | ["movf.s_2"] = "46000011FG",
426 | ["movf.s_3"] = "46000011FGC",
427 | ["movt.s_2"] = "46010011FG",
428 | ["movt.s_3"] = "46010011FGC",
429 | ["movz.s_3"] = "46000012FGT",
430 | ["movn.s_3"] = "46000013FGT",
431 | ["recip.s_2"] = "46000015FG",
432 | ["rsqrt.s_2"] = "46000016FG",
433 | ["cvt.d.s_2"] = "46000021FG",
434 | ["cvt.w.s_2"] = "46000024FG",
435 | ["cvt.l.s_2"] = "46000025FG",
436 | ["cvt.ps.s_3"] = "46000026FGH",
437 | ["c.f.s_2"] = "46000030GH",
438 | ["c.f.s_3"] = "46000030VGH",
439 | ["c.un.s_2"] = "46000031GH",
440 | ["c.un.s_3"] = "46000031VGH",
441 | ["c.eq.s_2"] = "46000032GH",
442 | ["c.eq.s_3"] = "46000032VGH",
443 | ["c.ueq.s_2"] = "46000033GH",
444 | ["c.ueq.s_3"] = "46000033VGH",
445 | ["c.olt.s_2"] = "46000034GH",
446 | ["c.olt.s_3"] = "46000034VGH",
447 | ["c.ult.s_2"] = "46000035GH",
448 | ["c.ult.s_3"] = "46000035VGH",
449 | ["c.ole.s_2"] = "46000036GH",
450 | ["c.ole.s_3"] = "46000036VGH",
451 | ["c.ule.s_2"] = "46000037GH",
452 | ["c.ule.s_3"] = "46000037VGH",
453 | ["c.sf.s_2"] = "46000038GH",
454 | ["c.sf.s_3"] = "46000038VGH",
455 | ["c.ngle.s_2"] = "46000039GH",
456 | ["c.ngle.s_3"] = "46000039VGH",
457 | ["c.seq.s_2"] = "4600003aGH",
458 | ["c.seq.s_3"] = "4600003aVGH",
459 | ["c.ngl.s_2"] = "4600003bGH",
460 | ["c.ngl.s_3"] = "4600003bVGH",
461 | ["c.lt.s_2"] = "4600003cGH",
462 | ["c.lt.s_3"] = "4600003cVGH",
463 | ["c.nge.s_2"] = "4600003dGH",
464 | ["c.nge.s_3"] = "4600003dVGH",
465 | ["c.le.s_2"] = "4600003eGH",
466 | ["c.le.s_3"] = "4600003eVGH",
467 | ["c.ngt.s_2"] = "4600003fGH",
468 | ["c.ngt.s_3"] = "4600003fVGH",
469 |
470 | ["add.d_3"] = "46200000FGH",
471 | ["sub.d_3"] = "46200001FGH",
472 | ["mul.d_3"] = "46200002FGH",
473 | ["div.d_3"] = "46200003FGH",
474 | ["sqrt.d_2"] = "46200004FG",
475 | ["abs.d_2"] = "46200005FG",
476 | ["mov.d_2"] = "46200006FG",
477 | ["neg.d_2"] = "46200007FG",
478 | ["round.l.d_2"] = "46200008FG",
479 | ["trunc.l.d_2"] = "46200009FG",
480 | ["ceil.l.d_2"] = "4620000aFG",
481 | ["floor.l.d_2"] = "4620000bFG",
482 | ["round.w.d_2"] = "4620000cFG",
483 | ["trunc.w.d_2"] = "4620000dFG",
484 | ["ceil.w.d_2"] = "4620000eFG",
485 | ["floor.w.d_2"] = "4620000fFG",
486 | ["movf.d_2"] = "46200011FG",
487 | ["movf.d_3"] = "46200011FGC",
488 | ["movt.d_2"] = "46210011FG",
489 | ["movt.d_3"] = "46210011FGC",
490 | ["movz.d_3"] = "46200012FGT",
491 | ["movn.d_3"] = "46200013FGT",
492 | ["recip.d_2"] = "46200015FG",
493 | ["rsqrt.d_2"] = "46200016FG",
494 | ["cvt.s.d_2"] = "46200020FG",
495 | ["cvt.w.d_2"] = "46200024FG",
496 | ["cvt.l.d_2"] = "46200025FG",
497 | ["c.f.d_2"] = "46200030GH",
498 | ["c.f.d_3"] = "46200030VGH",
499 | ["c.un.d_2"] = "46200031GH",
500 | ["c.un.d_3"] = "46200031VGH",
501 | ["c.eq.d_2"] = "46200032GH",
502 | ["c.eq.d_3"] = "46200032VGH",
503 | ["c.ueq.d_2"] = "46200033GH",
504 | ["c.ueq.d_3"] = "46200033VGH",
505 | ["c.olt.d_2"] = "46200034GH",
506 | ["c.olt.d_3"] = "46200034VGH",
507 | ["c.ult.d_2"] = "46200035GH",
508 | ["c.ult.d_3"] = "46200035VGH",
509 | ["c.ole.d_2"] = "46200036GH",
510 | ["c.ole.d_3"] = "46200036VGH",
511 | ["c.ule.d_2"] = "46200037GH",
512 | ["c.ule.d_3"] = "46200037VGH",
513 | ["c.sf.d_2"] = "46200038GH",
514 | ["c.sf.d_3"] = "46200038VGH",
515 | ["c.ngle.d_2"] = "46200039GH",
516 | ["c.ngle.d_3"] = "46200039VGH",
517 | ["c.seq.d_2"] = "4620003aGH",
518 | ["c.seq.d_3"] = "4620003aVGH",
519 | ["c.ngl.d_2"] = "4620003bGH",
520 | ["c.ngl.d_3"] = "4620003bVGH",
521 | ["c.lt.d_2"] = "4620003cGH",
522 | ["c.lt.d_3"] = "4620003cVGH",
523 | ["c.nge.d_2"] = "4620003dGH",
524 | ["c.nge.d_3"] = "4620003dVGH",
525 | ["c.le.d_2"] = "4620003eGH",
526 | ["c.le.d_3"] = "4620003eVGH",
527 | ["c.ngt.d_2"] = "4620003fGH",
528 | ["c.ngt.d_3"] = "4620003fVGH",
529 |
530 | ["add.ps_3"] = "46c00000FGH",
531 | ["sub.ps_3"] = "46c00001FGH",
532 | ["mul.ps_3"] = "46c00002FGH",
533 | ["abs.ps_2"] = "46c00005FG",
534 | ["mov.ps_2"] = "46c00006FG",
535 | ["neg.ps_2"] = "46c00007FG",
536 | ["movf.ps_2"] = "46c00011FG",
537 | ["movf.ps_3"] = "46c00011FGC",
538 | ["movt.ps_2"] = "46c10011FG",
539 | ["movt.ps_3"] = "46c10011FGC",
540 | ["movz.ps_3"] = "46c00012FGT",
541 | ["movn.ps_3"] = "46c00013FGT",
542 | ["cvt.s.pu_2"] = "46c00020FG",
543 | ["cvt.s.pl_2"] = "46c00028FG",
544 | ["pll.ps_3"] = "46c0002cFGH",
545 | ["plu.ps_3"] = "46c0002dFGH",
546 | ["pul.ps_3"] = "46c0002eFGH",
547 | ["puu.ps_3"] = "46c0002fFGH",
548 | ["c.f.ps_2"] = "46c00030GH",
549 | ["c.f.ps_3"] = "46c00030VGH",
550 | ["c.un.ps_2"] = "46c00031GH",
551 | ["c.un.ps_3"] = "46c00031VGH",
552 | ["c.eq.ps_2"] = "46c00032GH",
553 | ["c.eq.ps_3"] = "46c00032VGH",
554 | ["c.ueq.ps_2"] = "46c00033GH",
555 | ["c.ueq.ps_3"] = "46c00033VGH",
556 | ["c.olt.ps_2"] = "46c00034GH",
557 | ["c.olt.ps_3"] = "46c00034VGH",
558 | ["c.ult.ps_2"] = "46c00035GH",
559 | ["c.ult.ps_3"] = "46c00035VGH",
560 | ["c.ole.ps_2"] = "46c00036GH",
561 | ["c.ole.ps_3"] = "46c00036VGH",
562 | ["c.ule.ps_2"] = "46c00037GH",
563 | ["c.ule.ps_3"] = "46c00037VGH",
564 | ["c.sf.ps_2"] = "46c00038GH",
565 | ["c.sf.ps_3"] = "46c00038VGH",
566 | ["c.ngle.ps_2"] = "46c00039GH",
567 | ["c.ngle.ps_3"] = "46c00039VGH",
568 | ["c.seq.ps_2"] = "46c0003aGH",
569 | ["c.seq.ps_3"] = "46c0003aVGH",
570 | ["c.ngl.ps_2"] = "46c0003bGH",
571 | ["c.ngl.ps_3"] = "46c0003bVGH",
572 | ["c.lt.ps_2"] = "46c0003cGH",
573 | ["c.lt.ps_3"] = "46c0003cVGH",
574 | ["c.nge.ps_2"] = "46c0003dGH",
575 | ["c.nge.ps_3"] = "46c0003dVGH",
576 | ["c.le.ps_2"] = "46c0003eGH",
577 | ["c.le.ps_3"] = "46c0003eVGH",
578 | ["c.ngt.ps_2"] = "46c0003fGH",
579 | ["c.ngt.ps_3"] = "46c0003fVGH",
580 |
581 | ["cvt.s.w_2"] = "46800020FG",
582 | ["cvt.d.w_2"] = "46800021FG",
583 |
584 | ["cvt.s.l_2"] = "46a00020FG",
585 | ["cvt.d.l_2"] = "46a00021FG",
586 |
587 | -- Opcode COP1X.
588 | lwxc1_2 = "4c000000FX",
589 | ldxc1_2 = "4c000001FX",
590 | luxc1_2 = "4c000005FX",
591 | swxc1_2 = "4c000008FX",
592 | sdxc1_2 = "4c000009FX",
593 | suxc1_2 = "4c00000dFX",
594 | prefx_2 = "4c00000fMX",
595 | ["alnv.ps_4"] = "4c00001eFGHS",
596 | ["madd.s_4"] = "4c000020FRGH",
597 | ["madd.d_4"] = "4c000021FRGH",
598 | ["madd.ps_4"] = "4c000026FRGH",
599 | ["msub.s_4"] = "4c000028FRGH",
600 | ["msub.d_4"] = "4c000029FRGH",
601 | ["msub.ps_4"] = "4c00002eFRGH",
602 | ["nmadd.s_4"] = "4c000030FRGH",
603 | ["nmadd.d_4"] = "4c000031FRGH",
604 | ["nmadd.ps_4"] = "4c000036FRGH",
605 | ["nmsub.s_4"] = "4c000038FRGH",
606 | ["nmsub.d_4"] = "4c000039FRGH",
607 | ["nmsub.ps_4"] = "4c00003eFRGH",
608 | }
609 |
610 | ------------------------------------------------------------------------------
611 |
612 | local function parse_gpr(expr)
613 | local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$")
614 | local tp = map_type[tname or expr]
615 | if tp then
616 | local reg = ovreg or tp.reg
617 | if not reg then
618 | werror("type `"..(tname or expr).."' needs a register override")
619 | end
620 | expr = reg
621 | end
622 | local r = match(expr, "^r([1-3]?[0-9])$")
623 | if r then
624 | r = tonumber(r)
625 | if r <= 31 then return r, tp end
626 | end
627 | werror("bad register name `"..expr.."'")
628 | end
629 |
630 | local function parse_fpr(expr)
631 | local r = match(expr, "^f([1-3]?[0-9])$")
632 | if r then
633 | r = tonumber(r)
634 | if r <= 31 then return r end
635 | end
636 | werror("bad register name `"..expr.."'")
637 | end
638 |
639 | local function parse_imm(imm, bits, shift, scale, signed)
640 | local n = tonumber(imm)
641 | if n then
642 | if n % 2^scale == 0 then
643 | n = n / 2^scale
644 | if signed then
645 | if n >= 0 then
646 | if n < 2^(bits-1) then return n*2^shift end
647 | else
648 | if n >= -(2^(bits-1))-1 then return (n+2^bits)*2^shift end
649 | end
650 | else
651 | if n >= 0 and n <= 2^bits-1 then return n*2^shift end
652 | end
653 | end
654 | werror("out of range immediate `"..imm.."'")
655 | elseif match(imm, "^[rf]([1-3]?[0-9])$") or
656 | match(imm, "^([%w_]+):([rf][1-3]?[0-9])$") then
657 | werror("expected immediate operand, got register")
658 | else
659 | waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm)
660 | return 0
661 | end
662 | end
663 |
664 | local function parse_disp(disp)
665 | local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$")
666 | if imm then
667 | local r = parse_gpr(reg)*2^21
668 | local extname = match(imm, "^extern%s+(%S+)$")
669 | if extname then
670 | waction("REL_EXT", map_extern[extname], nil, 1)
671 | return r
672 | else
673 | return r + parse_imm(imm, 16, 0, 0, true)
674 | end
675 | end
676 | local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$")
677 | if reg and tailr ~= "" then
678 | local r, tp = parse_gpr(reg)
679 | if tp then
680 | waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr))
681 | return r*2^21
682 | end
683 | end
684 | werror("bad displacement `"..disp.."'")
685 | end
686 |
687 | local function parse_index(idx)
688 | local rt, rs = match(idx, "^(.*)%(([%w_:]+)%)$")
689 | if rt then
690 | rt = parse_gpr(rt)
691 | rs = parse_gpr(rs)
692 | return rt*2^16 + rs*2^21
693 | end
694 | werror("bad index `"..idx.."'")
695 | end
696 |
697 | local function parse_label(label, def)
698 | local prefix = sub(label, 1, 2)
699 | -- =>label (pc label reference)
700 | if prefix == "=>" then
701 | return "PC", 0, sub(label, 3)
702 | end
703 | -- ->name (global label reference)
704 | if prefix == "->" then
705 | return "LG", map_global[sub(label, 3)]
706 | end
707 | if def then
708 | -- [1-9] (local label definition)
709 | if match(label, "^[1-9]$") then
710 | return "LG", 10+tonumber(label)
711 | end
712 | else
713 | -- [<>][1-9] (local label reference)
714 | local dir, lnum = match(label, "^([<>])([1-9])$")
715 | if dir then -- Fwd: 1-9, Bkwd: 11-19.
716 | return "LG", lnum + (dir == ">" and 0 or 10)
717 | end
718 | -- extern label (extern label reference)
719 | local extname = match(label, "^extern%s+(%S+)$")
720 | if extname then
721 | return "EXT", map_extern[extname]
722 | end
723 | end
724 | werror("bad label `"..label.."'")
725 | end
726 |
727 | ------------------------------------------------------------------------------
728 |
729 | -- Handle opcodes defined with template strings.
730 | map_op[".template__"] = function(params, template, nparams)
731 | if not params then return sub(template, 9) end
732 | local op = tonumber(sub(template, 1, 8), 16)
733 | local n = 1
734 |
735 | -- Limit number of section buffer positions used by a single dasm_put().
736 | -- A single opcode needs a maximum of 2 positions (ins/ext).
737 | if secpos+2 > maxsecpos then wflush() end
738 | local pos = wpos()
739 |
740 | -- Process each character.
741 | for p in gmatch(sub(template, 9), ".") do
742 | if p == "D" then
743 | op = op + parse_gpr(params[n]) * 2^11; n = n + 1
744 | elseif p == "T" then
745 | op = op + parse_gpr(params[n]) * 2^16; n = n + 1
746 | elseif p == "S" then
747 | op = op + parse_gpr(params[n]) * 2^21; n = n + 1
748 | elseif p == "F" then
749 | op = op + parse_fpr(params[n]) * 2^6; n = n + 1
750 | elseif p == "G" then
751 | op = op + parse_fpr(params[n]) * 2^11; n = n + 1
752 | elseif p == "H" then
753 | op = op + parse_fpr(params[n]) * 2^16; n = n + 1
754 | elseif p == "R" then
755 | op = op + parse_fpr(params[n]) * 2^21; n = n + 1
756 | elseif p == "I" then
757 | op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1
758 | elseif p == "U" then
759 | op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1
760 | elseif p == "O" then
761 | op = op + parse_disp(params[n]); n = n + 1
762 | elseif p == "X" then
763 | op = op + parse_index(params[n]); n = n + 1
764 | elseif p == "B" or p == "J" then
765 | local mode, n, s = parse_label(params[n], false)
766 | if p == "B" then n = n + 2048 end
767 | waction("REL_"..mode, n, s, 1)
768 | n = n + 1
769 | elseif p == "A" then
770 | op = op + parse_imm(params[n], 5, 6, 0, false); n = n + 1
771 | elseif p == "M" then
772 | op = op + parse_imm(params[n], 5, 11, 0, false); n = n + 1
773 | elseif p == "N" then
774 | op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1
775 | elseif p == "C" then
776 | op = op + parse_imm(params[n], 3, 18, 0, false); n = n + 1
777 | elseif p == "V" then
778 | op = op + parse_imm(params[n], 3, 8, 0, false); n = n + 1
779 | elseif p == "W" then
780 | op = op + parse_imm(params[n], 3, 0, 0, false); n = n + 1
781 | elseif p == "Y" then
782 | op = op + parse_imm(params[n], 20, 6, 0, false); n = n + 1
783 | elseif p == "Z" then
784 | op = op + parse_imm(params[n], 10, 6, 0, false); n = n + 1
785 | elseif p == "=" then
786 | local d = ((op - op % 2^11) / 2^11) % 32
787 | op = op + d * 2^16 -- Copy D to T for clz, clo.
788 | else
789 | assert(false)
790 | end
791 | end
792 | wputpos(pos, op)
793 | end
794 |
795 | ------------------------------------------------------------------------------
796 |
797 | -- Pseudo-opcode to mark the position where the action list is to be emitted.
798 | map_op[".actionlist_1"] = function(params)
799 | if not params then return "cvar" end
800 | local name = params[1] -- No syntax check. You get to keep the pieces.
801 | wline(function(out) writeactions(out, name) end)
802 | end
803 |
804 | -- Pseudo-opcode to mark the position where the global enum is to be emitted.
805 | map_op[".globals_1"] = function(params)
806 | if not params then return "prefix" end
807 | local prefix = params[1] -- No syntax check. You get to keep the pieces.
808 | wline(function(out) writeglobals(out, prefix) end)
809 | end
810 |
811 | -- Pseudo-opcode to mark the position where the global names are to be emitted.
812 | map_op[".globalnames_1"] = function(params)
813 | if not params then return "cvar" end
814 | local name = params[1] -- No syntax check. You get to keep the pieces.
815 | wline(function(out) writeglobalnames(out, name) end)
816 | end
817 |
818 | -- Pseudo-opcode to mark the position where the extern names are to be emitted.
819 | map_op[".externnames_1"] = function(params)
820 | if not params then return "cvar" end
821 | local name = params[1] -- No syntax check. You get to keep the pieces.
822 | wline(function(out) writeexternnames(out, name) end)
823 | end
824 |
825 | ------------------------------------------------------------------------------
826 |
827 | -- Label pseudo-opcode (converted from trailing colon form).
828 | map_op[".label_1"] = function(params)
829 | if not params then return "[1-9] | ->global | =>pcexpr" end
830 | if secpos+1 > maxsecpos then wflush() end
831 | local mode, n, s = parse_label(params[1], true)
832 | if mode == "EXT" then werror("bad label definition") end
833 | waction("LABEL_"..mode, n, s, 1)
834 | end
835 |
836 | ------------------------------------------------------------------------------
837 |
838 | -- Pseudo-opcodes for data storage.
839 | map_op[".long_*"] = function(params)
840 | if not params then return "imm..." end
841 | for _,p in ipairs(params) do
842 | local n = tonumber(p)
843 | if not n then werror("bad immediate `"..p.."'") end
844 | if n < 0 then n = n + 2^32 end
845 | wputw(n)
846 | if secpos+2 > maxsecpos then wflush() end
847 | end
848 | end
849 |
850 | -- Alignment pseudo-opcode.
851 | map_op[".align_1"] = function(params)
852 | if not params then return "numpow2" end
853 | if secpos+1 > maxsecpos then wflush() end
854 | local align = tonumber(params[1])
855 | if align then
856 | local x = align
857 | -- Must be a power of 2 in the range (2 ... 256).
858 | for i=1,8 do
859 | x = x / 2
860 | if x == 1 then
861 | waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1.
862 | return
863 | end
864 | end
865 | end
866 | werror("bad alignment")
867 | end
868 |
869 | ------------------------------------------------------------------------------
870 |
871 | -- Pseudo-opcode for (primitive) type definitions (map to C types).
872 | map_op[".type_3"] = function(params, nparams)
873 | if not params then
874 | return nparams == 2 and "name, ctype" or "name, ctype, reg"
875 | end
876 | local name, ctype, reg = params[1], params[2], params[3]
877 | if not match(name, "^[%a_][%w_]*$") then
878 | werror("bad type name `"..name.."'")
879 | end
880 | local tp = map_type[name]
881 | if tp then
882 | werror("duplicate type `"..name.."'")
883 | end
884 | -- Add #type to defines. A bit unclean to put it in map_archdef.
885 | map_archdef["#"..name] = "sizeof("..ctype..")"
886 | -- Add new type and emit shortcut define.
887 | local num = ctypenum + 1
888 | map_type[name] = {
889 | ctype = ctype,
890 | ctypefmt = format("Dt%X(%%s)", num),
891 | reg = reg,
892 | }
893 | wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
894 | ctypenum = num
895 | end
896 | map_op[".type_2"] = map_op[".type_3"]
897 |
898 | -- Dump type definitions.
899 | local function dumptypes(out, lvl)
900 | local t = {}
901 | for name in pairs(map_type) do t[#t+1] = name end
902 | sort(t)
903 | out:write("Type definitions:\n")
904 | for _,name in ipairs(t) do
905 | local tp = map_type[name]
906 | local reg = tp.reg or ""
907 | out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
908 | end
909 | out:write("\n")
910 | end
911 |
912 | ------------------------------------------------------------------------------
913 |
914 | -- Set the current section.
915 | function _M.section(num)
916 | waction("SECTION", num)
917 | wflush(true) -- SECTION is a terminal action.
918 | end
919 |
920 | ------------------------------------------------------------------------------
921 |
922 | -- Dump architecture description.
923 | function _M.dumparch(out)
924 | out:write(format("DynASM %s version %s, released %s\n\n",
925 | _info.arch, _info.version, _info.release))
926 | dumpactions(out)
927 | end
928 |
929 | -- Dump all user defined elements.
930 | function _M.dumpdef(out, lvl)
931 | dumptypes(out, lvl)
932 | dumpglobals(out, lvl)
933 | dumpexterns(out, lvl)
934 | end
935 |
936 | ------------------------------------------------------------------------------
937 |
938 | -- Pass callbacks from/to the DynASM core.
939 | function _M.passcb(wl, we, wf, ww)
940 | wline, werror, wfatal, wwarn = wl, we, wf, ww
941 | return wflush
942 | end
943 |
944 | -- Setup the arch-specific module.
945 | function _M.setup(arch, opt)
946 | g_arch, g_opt = arch, opt
947 | end
948 |
949 | -- Merge the core maps and the arch-specific maps.
950 | function _M.mergemaps(map_coreop, map_def)
951 | setmetatable(map_op, { __index = map_coreop })
952 | setmetatable(map_def, { __index = map_archdef })
953 | return map_op, map_def
954 | end
955 |
956 | return _M
957 |
958 | ------------------------------------------------------------------------------
959 |
960 |
--------------------------------------------------------------------------------
/third_party/dynasm/dasm_ppc.h:
--------------------------------------------------------------------------------
1 | /*
2 | ** DynASM PPC encoding engine.
3 | ** Copyright (C) 2005-2012 Mike Pall. All rights reserved.
4 | ** Released under the MIT license. See dynasm.lua for full copyright notice.
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #define DASM_ARCH "ppc"
13 |
14 | #ifndef DASM_EXTERN
15 | #define DASM_EXTERN(a,b,c,d) 0
16 | #endif
17 |
18 | /* Action definitions. */
19 | enum {
20 | DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
21 | /* The following actions need a buffer position. */
22 | DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
23 | /* The following actions also have an argument. */
24 | DASM_REL_PC, DASM_LABEL_PC, DASM_IMM,
25 | DASM__MAX
26 | };
27 |
28 | /* Maximum number of section buffer positions for a single dasm_put() call. */
29 | #define DASM_MAXSECPOS 25
30 |
31 | /* DynASM encoder status codes. Action list offset or number are or'ed in. */
32 | #define DASM_S_OK 0x00000000
33 | #define DASM_S_NOMEM 0x01000000
34 | #define DASM_S_PHASE 0x02000000
35 | #define DASM_S_MATCH_SEC 0x03000000
36 | #define DASM_S_RANGE_I 0x11000000
37 | #define DASM_S_RANGE_SEC 0x12000000
38 | #define DASM_S_RANGE_LG 0x13000000
39 | #define DASM_S_RANGE_PC 0x14000000
40 | #define DASM_S_RANGE_REL 0x15000000
41 | #define DASM_S_UNDEF_LG 0x21000000
42 | #define DASM_S_UNDEF_PC 0x22000000
43 |
44 | /* Macros to convert positions (8 bit section + 24 bit index). */
45 | #define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
46 | #define DASM_POS2BIAS(pos) ((pos)&0xff000000)
47 | #define DASM_SEC2POS(sec) ((sec)<<24)
48 | #define DASM_POS2SEC(pos) ((pos)>>24)
49 | #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
50 |
51 | /* Action list type. */
52 | typedef const unsigned int *dasm_ActList;
53 |
54 | /* Per-section structure. */
55 | typedef struct dasm_Section {
56 | int *rbuf; /* Biased buffer pointer (negative section bias). */
57 | int *buf; /* True buffer pointer. */
58 | size_t bsize; /* Buffer size in bytes. */
59 | int pos; /* Biased buffer position. */
60 | int epos; /* End of biased buffer position - max single put. */
61 | int ofs; /* Byte offset into section. */
62 | } dasm_Section;
63 |
64 | /* Core structure holding the DynASM encoding state. */
65 | struct dasm_State {
66 | size_t psize; /* Allocated size of this structure. */
67 | dasm_ActList actionlist; /* Current actionlist pointer. */
68 | int *lglabels; /* Local/global chain/pos ptrs. */
69 | size_t lgsize;
70 | int *pclabels; /* PC label chains/pos ptrs. */
71 | size_t pcsize;
72 | void **globals; /* Array of globals (bias -10). */
73 | dasm_Section *section; /* Pointer to active section. */
74 | size_t codesize; /* Total size of all code sections. */
75 | int maxsection; /* 0 <= sectionidx < maxsection. */
76 | int status; /* Status code. */
77 | dasm_Section sections[1]; /* All sections. Alloc-extended. */
78 | };
79 |
80 | /* The size of the core structure depends on the max. number of sections. */
81 | #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
82 |
83 |
84 | /* Initialize DynASM state. */
85 | void dasm_init(Dst_DECL, int maxsection)
86 | {
87 | dasm_State *D;
88 | size_t psz = 0;
89 | int i;
90 | Dst_REF = NULL;
91 | DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
92 | D = Dst_REF;
93 | D->psize = psz;
94 | D->lglabels = NULL;
95 | D->lgsize = 0;
96 | D->pclabels = NULL;
97 | D->pcsize = 0;
98 | D->globals = NULL;
99 | D->maxsection = maxsection;
100 | for (i = 0; i < maxsection; i++) {
101 | D->sections[i].buf = NULL; /* Need this for pass3. */
102 | D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
103 | D->sections[i].bsize = 0;
104 | D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
105 | }
106 | }
107 |
108 | /* Free DynASM state. */
109 | void dasm_free(Dst_DECL)
110 | {
111 | dasm_State *D = Dst_REF;
112 | int i;
113 | for (i = 0; i < D->maxsection; i++)
114 | if (D->sections[i].buf)
115 | DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
116 | if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
117 | if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
118 | DASM_M_FREE(Dst, D, D->psize);
119 | }
120 |
121 | /* Setup global label array. Must be called before dasm_setup(). */
122 | void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
123 | {
124 | dasm_State *D = Dst_REF;
125 | D->globals = gl - 10; /* Negative bias to compensate for locals. */
126 | DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
127 | }
128 |
129 | /* Grow PC label array. Can be called after dasm_setup(), too. */
130 | void dasm_growpc(Dst_DECL, unsigned int maxpc)
131 | {
132 | dasm_State *D = Dst_REF;
133 | size_t osz = D->pcsize;
134 | DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
135 | memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
136 | }
137 |
138 | /* Setup encoder. */
139 | void dasm_setup(Dst_DECL, const void *actionlist)
140 | {
141 | dasm_State *D = Dst_REF;
142 | int i;
143 | D->actionlist = (dasm_ActList)actionlist;
144 | D->status = DASM_S_OK;
145 | D->section = &D->sections[0];
146 | memset((void *)D->lglabels, 0, D->lgsize);
147 | if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
148 | for (i = 0; i < D->maxsection; i++) {
149 | D->sections[i].pos = DASM_SEC2POS(i);
150 | D->sections[i].ofs = 0;
151 | }
152 | }
153 |
154 |
155 | #ifdef DASM_CHECKS
156 | #define CK(x, st) \
157 | do { if (!(x)) { \
158 | D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
159 | #define CKPL(kind, st) \
160 | do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
161 | D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
162 | #else
163 | #define CK(x, st) ((void)0)
164 | #define CKPL(kind, st) ((void)0)
165 | #endif
166 |
167 | /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
168 | void dasm_put(Dst_DECL, int start, ...)
169 | {
170 | va_list ap;
171 | dasm_State *D = Dst_REF;
172 | dasm_ActList p = D->actionlist + start;
173 | dasm_Section *sec = D->section;
174 | int pos = sec->pos, ofs = sec->ofs;
175 | int *b;
176 |
177 | if (pos >= sec->epos) {
178 | DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
179 | sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
180 | sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
181 | sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
182 | }
183 |
184 | b = sec->rbuf;
185 | b[pos++] = start;
186 |
187 | va_start(ap, start);
188 | while (1) {
189 | unsigned int ins = *p++;
190 | unsigned int action = (ins >> 16);
191 | if (action >= DASM__MAX) {
192 | ofs += 4;
193 | } else {
194 | int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
195 | switch (action) {
196 | case DASM_STOP: goto stop;
197 | case DASM_SECTION:
198 | n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
199 | D->section = &D->sections[n]; goto stop;
200 | case DASM_ESC: p++; ofs += 4; break;
201 | case DASM_REL_EXT: break;
202 | case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
203 | case DASM_REL_LG:
204 | n = (ins & 2047) - 10; pl = D->lglabels + n;
205 | if (n >= 0) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */
206 | pl += 10; n = *pl;
207 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
208 | goto linkrel;
209 | case DASM_REL_PC:
210 | pl = D->pclabels + n; CKPL(pc, PC);
211 | putrel:
212 | n = *pl;
213 | if (n < 0) { /* Label exists. Get label pos and store it. */
214 | b[pos] = -n;
215 | } else {
216 | linkrel:
217 | b[pos] = n; /* Else link to rel chain, anchored at label. */
218 | *pl = pos;
219 | }
220 | pos++;
221 | break;
222 | case DASM_LABEL_LG:
223 | pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
224 | case DASM_LABEL_PC:
225 | pl = D->pclabels + n; CKPL(pc, PC);
226 | putlabel:
227 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
228 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
229 | }
230 | *pl = -pos; /* Label exists now. */
231 | b[pos++] = ofs; /* Store pass1 offset estimate. */
232 | break;
233 | case DASM_IMM:
234 | #ifdef DASM_CHECKS
235 | CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
236 | #endif
237 | n >>= ((ins>>10)&31);
238 | #ifdef DASM_CHECKS
239 | if (ins & 0x8000)
240 | CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
241 | else
242 | CK((n>>((ins>>5)&31)) == 0, RANGE_I);
243 | #endif
244 | b[pos++] = n;
245 | break;
246 | }
247 | }
248 | }
249 | stop:
250 | va_end(ap);
251 | sec->pos = pos;
252 | sec->ofs = ofs;
253 | }
254 | #undef CK
255 |
256 | /* Pass 2: Link sections, shrink aligns, fix label offsets. */
257 | int dasm_link(Dst_DECL, size_t *szp)
258 | {
259 | dasm_State *D = Dst_REF;
260 | int secnum;
261 | int ofs = 0;
262 |
263 | #ifdef DASM_CHECKS
264 | *szp = 0;
265 | if (D->status != DASM_S_OK) return D->status;
266 | {
267 | int pc;
268 | for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
269 | if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
270 | }
271 | #endif
272 |
273 | { /* Handle globals not defined in this translation unit. */
274 | int idx;
275 | for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
276 | int n = D->lglabels[idx];
277 | /* Undefined label: Collapse rel chain and replace with marker (< 0). */
278 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
279 | }
280 | }
281 |
282 | /* Combine all code sections. No support for data sections (yet). */
283 | for (secnum = 0; secnum < D->maxsection; secnum++) {
284 | dasm_Section *sec = D->sections + secnum;
285 | int *b = sec->rbuf;
286 | int pos = DASM_SEC2POS(secnum);
287 | int lastpos = sec->pos;
288 |
289 | while (pos != lastpos) {
290 | dasm_ActList p = D->actionlist + b[pos++];
291 | while (1) {
292 | unsigned int ins = *p++;
293 | unsigned int action = (ins >> 16);
294 | switch (action) {
295 | case DASM_STOP: case DASM_SECTION: goto stop;
296 | case DASM_ESC: p++; break;
297 | case DASM_REL_EXT: break;
298 | case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
299 | case DASM_REL_LG: case DASM_REL_PC: pos++; break;
300 | case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
301 | case DASM_IMM: pos++; break;
302 | }
303 | }
304 | stop: (void)0;
305 | }
306 | ofs += sec->ofs; /* Next section starts right after current section. */
307 | }
308 |
309 | D->codesize = ofs; /* Total size of all code sections */
310 | *szp = ofs;
311 | return DASM_S_OK;
312 | }
313 |
314 | #ifdef DASM_CHECKS
315 | #define CK(x, st) \
316 | do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
317 | #else
318 | #define CK(x, st) ((void)0)
319 | #endif
320 |
321 | /* Pass 3: Encode sections. */
322 | int dasm_encode(Dst_DECL, void *buffer)
323 | {
324 | dasm_State *D = Dst_REF;
325 | char *base = (char *)buffer;
326 | unsigned int *cp = (unsigned int *)buffer;
327 | int secnum;
328 |
329 | /* Encode all code sections. No support for data sections (yet). */
330 | for (secnum = 0; secnum < D->maxsection; secnum++) {
331 | dasm_Section *sec = D->sections + secnum;
332 | int *b = sec->buf;
333 | int *endb = sec->rbuf + sec->pos;
334 |
335 | while (b != endb) {
336 | dasm_ActList p = D->actionlist + *b++;
337 | while (1) {
338 | unsigned int ins = *p++;
339 | unsigned int action = (ins >> 16);
340 | int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
341 | switch (action) {
342 | case DASM_STOP: case DASM_SECTION: goto stop;
343 | case DASM_ESC: *cp++ = *p++; break;
344 | case DASM_REL_EXT:
345 | n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1) - 4;
346 | goto patchrel;
347 | case DASM_ALIGN:
348 | ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000;
349 | break;
350 | case DASM_REL_LG:
351 | CK(n >= 0, UNDEF_LG);
352 | case DASM_REL_PC:
353 | CK(n >= 0, UNDEF_PC);
354 | n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base);
355 | patchrel:
356 | CK((n & 3) == 0 &&
357 | (((n+4) + ((ins & 2048) ? 0x00008000 : 0x02000000)) >>
358 | ((ins & 2048) ? 16 : 26)) == 0, RANGE_REL);
359 | cp[-1] |= ((n+4) & ((ins & 2048) ? 0x0000fffc: 0x03fffffc));
360 | break;
361 | case DASM_LABEL_LG:
362 | ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
363 | break;
364 | case DASM_LABEL_PC: break;
365 | case DASM_IMM:
366 | cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
367 | break;
368 | default: *cp++ = ins; break;
369 | }
370 | }
371 | stop: (void)0;
372 | }
373 | }
374 |
375 | if (base + D->codesize != (char *)cp) /* Check for phase errors. */
376 | return DASM_S_PHASE;
377 | return DASM_S_OK;
378 | }
379 | #undef CK
380 |
381 | /* Get PC label offset. */
382 | int dasm_getpclabel(Dst_DECL, unsigned int pc)
383 | {
384 | dasm_State *D = Dst_REF;
385 | if (pc*sizeof(int) < D->pcsize) {
386 | int pos = D->pclabels[pc];
387 | if (pos < 0) return *DASM_POS2PTR(D, -pos);
388 | if (pos > 0) return -1; /* Undefined. */
389 | }
390 | return -2; /* Unused or out of range. */
391 | }
392 |
393 | #ifdef DASM_CHECKS
394 | /* Optional sanity checker to call between isolated encoding steps. */
395 | int dasm_checkstep(Dst_DECL, int secmatch)
396 | {
397 | dasm_State *D = Dst_REF;
398 | if (D->status == DASM_S_OK) {
399 | int i;
400 | for (i = 1; i <= 9; i++) {
401 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
402 | D->lglabels[i] = 0;
403 | }
404 | }
405 | if (D->status == DASM_S_OK && secmatch >= 0 &&
406 | D->section != &D->sections[secmatch])
407 | D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
408 | return D->status;
409 | }
410 | #endif
411 |
412 |
--------------------------------------------------------------------------------
/third_party/dynasm/dasm_ppc.lua:
--------------------------------------------------------------------------------
1 | ------------------------------------------------------------------------------
2 | -- DynASM PPC module.
3 | --
4 | -- Copyright (C) 2005-2012 Mike Pall. All rights reserved.
5 | -- See dynasm.lua for full copyright notice.
6 | ------------------------------------------------------------------------------
7 |
8 | -- Module information:
9 | local _info = {
10 | arch = "ppc",
11 | description = "DynASM PPC module",
12 | version = "1.3.0",
13 | vernum = 10300,
14 | release = "2011-05-05",
15 | author = "Mike Pall",
16 | license = "MIT",
17 | }
18 |
19 | -- Exported glue functions for the arch-specific module.
20 | local _M = { _info = _info }
21 |
22 | -- Cache library functions.
23 | local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
24 | local assert, setmetatable = assert, setmetatable
25 | local _s = string
26 | local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
27 | local match, gmatch = _s.match, _s.gmatch
28 | local concat, sort = table.concat, table.sort
29 |
30 | -- Inherited tables and callbacks.
31 | local g_opt, g_arch
32 | local wline, werror, wfatal, wwarn
33 |
34 | -- Action name list.
35 | -- CHECK: Keep this in sync with the C code!
36 | local action_names = {
37 | "STOP", "SECTION", "ESC", "REL_EXT",
38 | "ALIGN", "REL_LG", "LABEL_LG",
39 | "REL_PC", "LABEL_PC", "IMM",
40 | }
41 |
42 | -- Maximum number of section buffer positions for dasm_put().
43 | -- CHECK: Keep this in sync with the C code!
44 | local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
45 |
46 | -- Action name -> action number.
47 | local map_action = {}
48 | for n,name in ipairs(action_names) do
49 | map_action[name] = n-1
50 | end
51 |
52 | -- Action list buffer.
53 | local actlist = {}
54 |
55 | -- Argument list for next dasm_put(). Start with offset 0 into action list.
56 | local actargs = { 0 }
57 |
58 | -- Current number of section buffer positions for dasm_put().
59 | local secpos = 1
60 |
61 | ------------------------------------------------------------------------------
62 |
63 | -- Return 8 digit hex number.
64 | local function tohex(x)
65 | return sub(format("%08x", x), -8) -- Avoid 64 bit portability problem in Lua.
66 | end
67 |
68 | -- Dump action names and numbers.
69 | local function dumpactions(out)
70 | out:write("DynASM encoding engine action codes:\n")
71 | for n,name in ipairs(action_names) do
72 | local num = map_action[name]
73 | out:write(format(" %-10s %02X %d\n", name, num, num))
74 | end
75 | out:write("\n")
76 | end
77 |
78 | -- Write action list buffer as a huge static C array.
79 | local function writeactions(out, name)
80 | local nn = #actlist
81 | if nn == 0 then nn = 1; actlist[0] = map_action.STOP end
82 | out:write("static const unsigned int ", name, "[", nn, "] = {\n")
83 | for i = 1,nn-1 do
84 | assert(out:write("0x", tohex(actlist[i]), ",\n"))
85 | end
86 | assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n"))
87 | end
88 |
89 | ------------------------------------------------------------------------------
90 |
91 | -- Add word to action list.
92 | local function wputxw(n)
93 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
94 | actlist[#actlist+1] = n
95 | end
96 |
97 | -- Add action to list with optional arg. Advance buffer pos, too.
98 | local function waction(action, val, a, num)
99 | local w = assert(map_action[action], "bad action name `"..action.."'")
100 | wputxw(w * 0x10000 + (val or 0))
101 | if a then actargs[#actargs+1] = a end
102 | if a or num then secpos = secpos + (num or 1) end
103 | end
104 |
105 | -- Flush action list (intervening C code or buffer pos overflow).
106 | local function wflush(term)
107 | if #actlist == actargs[1] then return end -- Nothing to flush.
108 | if not term then waction("STOP") end -- Terminate action list.
109 | wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true)
110 | actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
111 | secpos = 1 -- The actionlist offset occupies a buffer position, too.
112 | end
113 |
114 | -- Put escaped word.
115 | local function wputw(n)
116 | if n <= 0xffffff then waction("ESC") end
117 | wputxw(n)
118 | end
119 |
120 | -- Reserve position for word.
121 | local function wpos()
122 | local pos = #actlist+1
123 | actlist[pos] = ""
124 | return pos
125 | end
126 |
127 | -- Store word to reserved position.
128 | local function wputpos(pos, n)
129 | assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
130 | actlist[pos] = n
131 | end
132 |
133 | ------------------------------------------------------------------------------
134 |
135 | -- Global label name -> global label number. With auto assignment on 1st use.
136 | local next_global = 20
137 | local map_global = setmetatable({}, { __index = function(t, name)
138 | if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
139 | local n = next_global
140 | if n > 2047 then werror("too many global labels") end
141 | next_global = n + 1
142 | t[name] = n
143 | return n
144 | end})
145 |
146 | -- Dump global labels.
147 | local function dumpglobals(out, lvl)
148 | local t = {}
149 | for name, n in pairs(map_global) do t[n] = name end
150 | out:write("Global labels:\n")
151 | for i=20,next_global-1 do
152 | out:write(format(" %s\n", t[i]))
153 | end
154 | out:write("\n")
155 | end
156 |
157 | -- Write global label enum.
158 | local function writeglobals(out, prefix)
159 | local t = {}
160 | for name, n in pairs(map_global) do t[n] = name end
161 | out:write("enum {\n")
162 | for i=20,next_global-1 do
163 | out:write(" ", prefix, t[i], ",\n")
164 | end
165 | out:write(" ", prefix, "_MAX\n};\n")
166 | end
167 |
168 | -- Write global label names.
169 | local function writeglobalnames(out, name)
170 | local t = {}
171 | for name, n in pairs(map_global) do t[n] = name end
172 | out:write("static const char *const ", name, "[] = {\n")
173 | for i=20,next_global-1 do
174 | out:write(" \"", t[i], "\",\n")
175 | end
176 | out:write(" (const char *)0\n};\n")
177 | end
178 |
179 | ------------------------------------------------------------------------------
180 |
181 | -- Extern label name -> extern label number. With auto assignment on 1st use.
182 | local next_extern = 0
183 | local map_extern_ = {}
184 | local map_extern = setmetatable({}, { __index = function(t, name)
185 | -- No restrictions on the name for now.
186 | local n = next_extern
187 | if n > 2047 then werror("too many extern labels") end
188 | next_extern = n + 1
189 | t[name] = n
190 | map_extern_[n] = name
191 | return n
192 | end})
193 |
194 | -- Dump extern labels.
195 | local function dumpexterns(out, lvl)
196 | out:write("Extern labels:\n")
197 | for i=0,next_extern-1 do
198 | out:write(format(" %s\n", map_extern_[i]))
199 | end
200 | out:write("\n")
201 | end
202 |
203 | -- Write extern label names.
204 | local function writeexternnames(out, name)
205 | out:write("static const char *const ", name, "[] = {\n")
206 | for i=0,next_extern-1 do
207 | out:write(" \"", map_extern_[i], "\",\n")
208 | end
209 | out:write(" (const char *)0\n};\n")
210 | end
211 |
212 | ------------------------------------------------------------------------------
213 |
214 | -- Arch-specific maps.
215 | local map_archdef = { sp = "r1" } -- Ext. register name -> int. name.
216 |
217 | local map_type = {} -- Type name -> { ctype, reg }
218 | local ctypenum = 0 -- Type number (for Dt... macros).
219 |
220 | -- Reverse defines for registers.
221 | function _M.revdef(s)
222 | if s == "r1" then return "sp" end
223 | return s
224 | end
225 |
226 | local map_cond = {
227 | lt = 0, gt = 1, eq = 2, so = 3,
228 | ge = 4, le = 5, ne = 6, ns = 7,
229 | }
230 |
231 | ------------------------------------------------------------------------------
232 |
233 | -- Template strings for PPC instructions.
234 | local map_op = {
235 | tdi_3 = "08000000ARI",
236 | twi_3 = "0c000000ARI",
237 | mulli_3 = "1c000000RRI",
238 | subfic_3 = "20000000RRI",
239 | cmplwi_3 = "28000000XRU",
240 | cmplwi_2 = "28000000-RU",
241 | cmpldi_3 = "28200000XRU",
242 | cmpldi_2 = "28200000-RU",
243 | cmpwi_3 = "2c000000XRI",
244 | cmpwi_2 = "2c000000-RI",
245 | cmpdi_3 = "2c200000XRI",
246 | cmpdi_2 = "2c200000-RI",
247 | addic_3 = "30000000RRI",
248 | ["addic._3"] = "34000000RRI",
249 | addi_3 = "38000000RR0I",
250 | li_2 = "38000000RI",
251 | la_2 = "38000000RD",
252 | addis_3 = "3c000000RR0I",
253 | lis_2 = "3c000000RI",
254 | lus_2 = "3c000000RU",
255 | bc_3 = "40000000AAK",
256 | bcl_3 = "40000001AAK",
257 | bdnz_1 = "42000000K",
258 | bdz_1 = "42400000K",
259 | sc_0 = "44000000",
260 | b_1 = "48000000J",
261 | bl_1 = "48000001J",
262 | rlwimi_5 = "50000000RR~AAA.",
263 | rlwinm_5 = "54000000RR~AAA.",
264 | rlwnm_5 = "5c000000RR~RAA.",
265 | ori_3 = "60000000RR~U",
266 | nop_0 = "60000000",
267 | oris_3 = "64000000RR~U",
268 | xori_3 = "68000000RR~U",
269 | xoris_3 = "6c000000RR~U",
270 | ["andi._3"] = "70000000RR~U",
271 | ["andis._3"] = "74000000RR~U",
272 | lwz_2 = "80000000RD",
273 | lwzu_2 = "84000000RD",
274 | lbz_2 = "88000000RD",
275 | lbzu_2 = "8c000000RD",
276 | stw_2 = "90000000RD",
277 | stwu_2 = "94000000RD",
278 | stb_2 = "98000000RD",
279 | stbu_2 = "9c000000RD",
280 | lhz_2 = "a0000000RD",
281 | lhzu_2 = "a4000000RD",
282 | lha_2 = "a8000000RD",
283 | lhau_2 = "ac000000RD",
284 | sth_2 = "b0000000RD",
285 | sthu_2 = "b4000000RD",
286 | lmw_2 = "b8000000RD",
287 | stmw_2 = "bc000000RD",
288 | lfs_2 = "c0000000FD",
289 | lfsu_2 = "c4000000FD",
290 | lfd_2 = "c8000000FD",
291 | lfdu_2 = "cc000000FD",
292 | stfs_2 = "d0000000FD",
293 | stfsu_2 = "d4000000FD",
294 | stfd_2 = "d8000000FD",
295 | stfdu_2 = "dc000000FD",
296 | ld_2 = "e8000000RD", -- NYI: displacement must be divisible by 4.
297 | ldu_2 = "e8000001RD",
298 | lwa_2 = "e8000002RD",
299 | std_2 = "f8000000RD",
300 | stdu_2 = "f8000001RD",
301 |
302 | -- Primary opcode 19:
303 | mcrf_2 = "4c000000XX",
304 | isync_0 = "4c00012c",
305 | crnor_3 = "4c000042CCC",
306 | crnot_2 = "4c000042CC=",
307 | crandc_3 = "4c000102CCC",
308 | crxor_3 = "4c000182CCC",
309 | crclr_1 = "4c000182C==",
310 | crnand_3 = "4c0001c2CCC",
311 | crand_3 = "4c000202CCC",
312 | creqv_3 = "4c000242CCC",
313 | crset_1 = "4c000242C==",
314 | crorc_3 = "4c000342CCC",
315 | cror_3 = "4c000382CCC",
316 | crmove_2 = "4c000382CC=",
317 | bclr_2 = "4c000020AA",
318 | bclrl_2 = "4c000021AA",
319 | bcctr_2 = "4c000420AA",
320 | bcctrl_2 = "4c000421AA",
321 | blr_0 = "4e800020",
322 | blrl_0 = "4e800021",
323 | bctr_0 = "4e800420",
324 | bctrl_0 = "4e800421",
325 |
326 | -- Primary opcode 31:
327 | cmpw_3 = "7c000000XRR",
328 | cmpw_2 = "7c000000-RR",
329 | cmpd_3 = "7c200000XRR",
330 | cmpd_2 = "7c200000-RR",
331 | tw_3 = "7c000008ARR",
332 | subfc_3 = "7c000010RRR.",
333 | subc_3 = "7c000010RRR~.",
334 | mulhdu_3 = "7c000012RRR.",
335 | addc_3 = "7c000014RRR.",
336 | mulhwu_3 = "7c000016RRR.",
337 | isel_4 = "7c00001eRRRC",
338 | isellt_3 = "7c00001eRRR",
339 | iselgt_3 = "7c00005eRRR",
340 | iseleq_3 = "7c00009eRRR",
341 | mfcr_1 = "7c000026R",
342 | mtcrf_2 = "7c000120GR",
343 | -- NYI: mtocrf, mfocrf
344 | lwarx_3 = "7c000028RR0R",
345 | ldx_3 = "7c00002aRR0R",
346 | lwzx_3 = "7c00002eRR0R",
347 | slw_3 = "7c000030RR~R.",
348 | cntlzw_2 = "7c000034RR~",
349 | sld_3 = "7c000036RR~R.",
350 | and_3 = "7c000038RR~R.",
351 | cmplw_3 = "7c000040XRR",
352 | cmplw_2 = "7c000040-RR",
353 | cmpld_3 = "7c200040XRR",
354 | cmpld_2 = "7c200040-RR",
355 | subf_3 = "7c000050RRR.",
356 | sub_3 = "7c000050RRR~.",
357 | ldux_3 = "7c00006aRR0R",
358 | dcbst_2 = "7c00006c-RR",
359 | lwzux_3 = "7c00006eRR0R",
360 | cntlzd_2 = "7c000074RR~",
361 | andc_3 = "7c000078RR~R.",
362 | td_3 = "7c000088ARR",
363 | mulhd_3 = "7c000092RRR.",
364 | mulhw_3 = "7c000096RRR.",
365 | ldarx_3 = "7c0000a8RR0R",
366 | dcbf_2 = "7c0000ac-RR",
367 | lbzx_3 = "7c0000aeRR0R",
368 | neg_2 = "7c0000d0RR.",
369 | lbzux_3 = "7c0000eeRR0R",
370 | popcntb_2 = "7c0000f4RR~",
371 | not_2 = "7c0000f8RR~%.",
372 | nor_3 = "7c0000f8RR~R.",
373 | subfe_3 = "7c000110RRR.",
374 | sube_3 = "7c000110RRR~.",
375 | adde_3 = "7c000114RRR.",
376 | stdx_3 = "7c00012aRR0R",
377 | stwcx_3 = "7c00012cRR0R.",
378 | stwx_3 = "7c00012eRR0R",
379 | prtyw_2 = "7c000134RR~",
380 | stdux_3 = "7c00016aRR0R",
381 | stwux_3 = "7c00016eRR0R",
382 | prtyd_2 = "7c000174RR~",
383 | subfze_2 = "7c000190RR.",
384 | addze_2 = "7c000194RR.",
385 | stdcx_3 = "7c0001acRR0R.",
386 | stbx_3 = "7c0001aeRR0R",
387 | subfme_2 = "7c0001d0RR.",
388 | mulld_3 = "7c0001d2RRR.",
389 | addme_2 = "7c0001d4RR.",
390 | mullw_3 = "7c0001d6RRR.",
391 | dcbtst_2 = "7c0001ec-RR",
392 | stbux_3 = "7c0001eeRR0R",
393 | add_3 = "7c000214RRR.",
394 | dcbt_2 = "7c00022c-RR",
395 | lhzx_3 = "7c00022eRR0R",
396 | eqv_3 = "7c000238RR~R.",
397 | eciwx_3 = "7c00026cRR0R",
398 | lhzux_3 = "7c00026eRR0R",
399 | xor_3 = "7c000278RR~R.",
400 | mfspefscr_1 = "7c0082a6R",
401 | mfxer_1 = "7c0102a6R",
402 | mflr_1 = "7c0802a6R",
403 | mfctr_1 = "7c0902a6R",
404 | lwax_3 = "7c0002aaRR0R",
405 | lhax_3 = "7c0002aeRR0R",
406 | mftb_1 = "7c0c42e6R",
407 | mftbu_1 = "7c0d42e6R",
408 | lwaux_3 = "7c0002eaRR0R",
409 | lhaux_3 = "7c0002eeRR0R",
410 | sthx_3 = "7c00032eRR0R",
411 | orc_3 = "7c000338RR~R.",
412 | ecowx_3 = "7c00036cRR0R",
413 | sthux_3 = "7c00036eRR0R",
414 | or_3 = "7c000378RR~R.",
415 | mr_2 = "7c000378RR~%.",
416 | divdu_3 = "7c000392RRR.",
417 | divwu_3 = "7c000396RRR.",
418 | mtspefscr_1 = "7c0083a6R",
419 | mtxer_1 = "7c0103a6R",
420 | mtlr_1 = "7c0803a6R",
421 | mtctr_1 = "7c0903a6R",
422 | dcbi_2 = "7c0003ac-RR",
423 | nand_3 = "7c0003b8RR~R.",
424 | divd_3 = "7c0003d2RRR.",
425 | divw_3 = "7c0003d6RRR.",
426 | cmpb_3 = "7c0003f8RR~R.",
427 | mcrxr_1 = "7c000400X",
428 | subfco_3 = "7c000410RRR.",
429 | subco_3 = "7c000410RRR~.",
430 | addco_3 = "7c000414RRR.",
431 | ldbrx_3 = "7c000428RR0R",
432 | lswx_3 = "7c00042aRR0R",
433 | lwbrx_3 = "7c00042cRR0R",
434 | lfsx_3 = "7c00042eFR0R",
435 | srw_3 = "7c000430RR~R.",
436 | srd_3 = "7c000436RR~R.",
437 | subfo_3 = "7c000450RRR.",
438 | subo_3 = "7c000450RRR~.",
439 | lfsux_3 = "7c00046eFR0R",
440 | lswi_3 = "7c0004aaRR0A",
441 | sync_0 = "7c0004ac",
442 | lwsync_0 = "7c2004ac",
443 | ptesync_0 = "7c4004ac",
444 | lfdx_3 = "7c0004aeFR0R",
445 | nego_2 = "7c0004d0RR.",
446 | lfdux_3 = "7c0004eeFR0R",
447 | subfeo_3 = "7c000510RRR.",
448 | subeo_3 = "7c000510RRR~.",
449 | addeo_3 = "7c000514RRR.",
450 | stdbrx_3 = "7c000528RR0R",
451 | stswx_3 = "7c00052aRR0R",
452 | stwbrx_3 = "7c00052cRR0R",
453 | stfsx_3 = "7c00052eFR0R",
454 | stfsux_3 = "7c00056eFR0R",
455 | subfzeo_2 = "7c000590RR.",
456 | addzeo_2 = "7c000594RR.",
457 | stswi_3 = "7c0005aaRR0A",
458 | stfdx_3 = "7c0005aeFR0R",
459 | subfmeo_2 = "7c0005d0RR.",
460 | mulldo_3 = "7c0005d2RRR.",
461 | addmeo_2 = "7c0005d4RR.",
462 | mullwo_3 = "7c0005d6RRR.",
463 | dcba_2 = "7c0005ec-RR",
464 | stfdux_3 = "7c0005eeFR0R",
465 | addo_3 = "7c000614RRR.",
466 | lhbrx_3 = "7c00062cRR0R",
467 | sraw_3 = "7c000630RR~R.",
468 | srad_3 = "7c000634RR~R.",
469 | srawi_3 = "7c000670RR~A.",
470 | eieio_0 = "7c0006ac",
471 | lfiwax_3 = "7c0006aeFR0R",
472 | sthbrx_3 = "7c00072cRR0R",
473 | extsh_2 = "7c000734RR~.",
474 | extsb_2 = "7c000774RR~.",
475 | divduo_3 = "7c000792RRR.",
476 | divwou_3 = "7c000796RRR.",
477 | icbi_2 = "7c0007ac-RR",
478 | stfiwx_3 = "7c0007aeFR0R",
479 | extsw_2 = "7c0007b4RR~.",
480 | divdo_3 = "7c0007d2RRR.",
481 | divwo_3 = "7c0007d6RRR.",
482 | dcbz_2 = "7c0007ec-RR",
483 |
484 | -- Primary opcode 59:
485 | fdivs_3 = "ec000024FFF.",
486 | fsubs_3 = "ec000028FFF.",
487 | fadds_3 = "ec00002aFFF.",
488 | fsqrts_2 = "ec00002cF-F.",
489 | fres_2 = "ec000030F-F.",
490 | fmuls_3 = "ec000032FF-F.",
491 | frsqrtes_2 = "ec000034F-F.",
492 | fmsubs_4 = "ec000038FFFF~.",
493 | fmadds_4 = "ec00003aFFFF~.",
494 | fnmsubs_4 = "ec00003cFFFF~.",
495 | fnmadds_4 = "ec00003eFFFF~.",
496 |
497 | -- Primary opcode 63:
498 | fdiv_3 = "fc000024FFF.",
499 | fsub_3 = "fc000028FFF.",
500 | fadd_3 = "fc00002aFFF.",
501 | fsqrt_2 = "fc00002cF-F.",
502 | fsel_4 = "fc00002eFFFF~.",
503 | fre_2 = "fc000030F-F.",
504 | fmul_3 = "fc000032FF-F.",
505 | frsqrte_2 = "fc000034F-F.",
506 | fmsub_4 = "fc000038FFFF~.",
507 | fmadd_4 = "fc00003aFFFF~.",
508 | fnmsub_4 = "fc00003cFFFF~.",
509 | fnmadd_4 = "fc00003eFFFF~.",
510 | fcmpu_3 = "fc000000XFF",
511 | fcpsgn_3 = "fc000010FFF.",
512 | fcmpo_3 = "fc000040XFF",
513 | mtfsb1_1 = "fc00004cA",
514 | fneg_2 = "fc000050F-F.",
515 | mcrfs_2 = "fc000080XX",
516 | mtfsb0_1 = "fc00008cA",
517 | fmr_2 = "fc000090F-F.",
518 | frsp_2 = "fc000018F-F.",
519 | fctiw_2 = "fc00001cF-F.",
520 | fctiwz_2 = "fc00001eF-F.",
521 | mtfsfi_2 = "fc00010cAA", -- NYI: upshift.
522 | fnabs_2 = "fc000110F-F.",
523 | fabs_2 = "fc000210F-F.",
524 | frin_2 = "fc000310F-F.",
525 | friz_2 = "fc000350F-F.",
526 | frip_2 = "fc000390F-F.",
527 | frim_2 = "fc0003d0F-F.",
528 | mffs_1 = "fc00048eF.",
529 | -- NYI: mtfsf, mtfsb0, mtfsb1.
530 | fctid_2 = "fc00065cF-F.",
531 | fctidz_2 = "fc00065eF-F.",
532 | fcfid_2 = "fc00069cF-F.",
533 |
534 | -- Primary opcode 4, SPE APU extension:
535 | evaddw_3 = "10000200RRR",
536 | evaddiw_3 = "10000202RAR~",
537 | evsubw_3 = "10000204RRR~",
538 | evsubiw_3 = "10000206RAR~",
539 | evabs_2 = "10000208RR",
540 | evneg_2 = "10000209RR",
541 | evextsb_2 = "1000020aRR",
542 | evextsh_2 = "1000020bRR",
543 | evrndw_2 = "1000020cRR",
544 | evcntlzw_2 = "1000020dRR",
545 | evcntlsw_2 = "1000020eRR",
546 | brinc_3 = "1000020fRRR",
547 | evand_3 = "10000211RRR",
548 | evandc_3 = "10000212RRR",
549 | evxor_3 = "10000216RRR",
550 | evor_3 = "10000217RRR",
551 | evmr_2 = "10000217RR=",
552 | evnor_3 = "10000218RRR",
553 | evnot_2 = "10000218RR=",
554 | eveqv_3 = "10000219RRR",
555 | evorc_3 = "1000021bRRR",
556 | evnand_3 = "1000021eRRR",
557 | evsrwu_3 = "10000220RRR",
558 | evsrws_3 = "10000221RRR",
559 | evsrwiu_3 = "10000222RRA",
560 | evsrwis_3 = "10000223RRA",
561 | evslw_3 = "10000224RRR",
562 | evslwi_3 = "10000226RRA",
563 | evrlw_3 = "10000228RRR",
564 | evsplati_2 = "10000229RS",
565 | evrlwi_3 = "1000022aRRA",
566 | evsplatfi_2 = "1000022bRS",
567 | evmergehi_3 = "1000022cRRR",
568 | evmergelo_3 = "1000022dRRR",
569 | evcmpgtu_3 = "10000230XRR",
570 | evcmpgtu_2 = "10000230-RR",
571 | evcmpgts_3 = "10000231XRR",
572 | evcmpgts_2 = "10000231-RR",
573 | evcmpltu_3 = "10000232XRR",
574 | evcmpltu_2 = "10000232-RR",
575 | evcmplts_3 = "10000233XRR",
576 | evcmplts_2 = "10000233-RR",
577 | evcmpeq_3 = "10000234XRR",
578 | evcmpeq_2 = "10000234-RR",
579 | evsel_4 = "10000278RRRW",
580 | evsel_3 = "10000278RRR",
581 | evfsadd_3 = "10000280RRR",
582 | evfssub_3 = "10000281RRR",
583 | evfsabs_2 = "10000284RR",
584 | evfsnabs_2 = "10000285RR",
585 | evfsneg_2 = "10000286RR",
586 | evfsmul_3 = "10000288RRR",
587 | evfsdiv_3 = "10000289RRR",
588 | evfscmpgt_3 = "1000028cXRR",
589 | evfscmpgt_2 = "1000028c-RR",
590 | evfscmplt_3 = "1000028dXRR",
591 | evfscmplt_2 = "1000028d-RR",
592 | evfscmpeq_3 = "1000028eXRR",
593 | evfscmpeq_2 = "1000028e-RR",
594 | evfscfui_2 = "10000290R-R",
595 | evfscfsi_2 = "10000291R-R",
596 | evfscfuf_2 = "10000292R-R",
597 | evfscfsf_2 = "10000293R-R",
598 | evfsctui_2 = "10000294R-R",
599 | evfsctsi_2 = "10000295R-R",
600 | evfsctuf_2 = "10000296R-R",
601 | evfsctsf_2 = "10000297R-R",
602 | evfsctuiz_2 = "10000298R-R",
603 | evfsctsiz_2 = "1000029aR-R",
604 | evfststgt_3 = "1000029cXRR",
605 | evfststgt_2 = "1000029c-RR",
606 | evfststlt_3 = "1000029dXRR",
607 | evfststlt_2 = "1000029d-RR",
608 | evfststeq_3 = "1000029eXRR",
609 | evfststeq_2 = "1000029e-RR",
610 | efsadd_3 = "100002c0RRR",
611 | efssub_3 = "100002c1RRR",
612 | efsabs_2 = "100002c4RR",
613 | efsnabs_2 = "100002c5RR",
614 | efsneg_2 = "100002c6RR",
615 | efsmul_3 = "100002c8RRR",
616 | efsdiv_3 = "100002c9RRR",
617 | efscmpgt_3 = "100002ccXRR",
618 | efscmpgt_2 = "100002cc-RR",
619 | efscmplt_3 = "100002cdXRR",
620 | efscmplt_2 = "100002cd-RR",
621 | efscmpeq_3 = "100002ceXRR",
622 | efscmpeq_2 = "100002ce-RR",
623 | efscfd_2 = "100002cfR-R",
624 | efscfui_2 = "100002d0R-R",
625 | efscfsi_2 = "100002d1R-R",
626 | efscfuf_2 = "100002d2R-R",
627 | efscfsf_2 = "100002d3R-R",
628 | efsctui_2 = "100002d4R-R",
629 | efsctsi_2 = "100002d5R-R",
630 | efsctuf_2 = "100002d6R-R",
631 | efsctsf_2 = "100002d7R-R",
632 | efsctuiz_2 = "100002d8R-R",
633 | efsctsiz_2 = "100002daR-R",
634 | efststgt_3 = "100002dcXRR",
635 | efststgt_2 = "100002dc-RR",
636 | efststlt_3 = "100002ddXRR",
637 | efststlt_2 = "100002dd-RR",
638 | efststeq_3 = "100002deXRR",
639 | efststeq_2 = "100002de-RR",
640 | efdadd_3 = "100002e0RRR",
641 | efdsub_3 = "100002e1RRR",
642 | efdcfuid_2 = "100002e2R-R",
643 | efdcfsid_2 = "100002e3R-R",
644 | efdabs_2 = "100002e4RR",
645 | efdnabs_2 = "100002e5RR",
646 | efdneg_2 = "100002e6RR",
647 | efdmul_3 = "100002e8RRR",
648 | efddiv_3 = "100002e9RRR",
649 | efdctuidz_2 = "100002eaR-R",
650 | efdctsidz_2 = "100002ebR-R",
651 | efdcmpgt_3 = "100002ecXRR",
652 | efdcmpgt_2 = "100002ec-RR",
653 | efdcmplt_3 = "100002edXRR",
654 | efdcmplt_2 = "100002ed-RR",
655 | efdcmpeq_3 = "100002eeXRR",
656 | efdcmpeq_2 = "100002ee-RR",
657 | efdcfs_2 = "100002efR-R",
658 | efdcfui_2 = "100002f0R-R",
659 | efdcfsi_2 = "100002f1R-R",
660 | efdcfuf_2 = "100002f2R-R",
661 | efdcfsf_2 = "100002f3R-R",
662 | efdctui_2 = "100002f4R-R",
663 | efdctsi_2 = "100002f5R-R",
664 | efdctuf_2 = "100002f6R-R",
665 | efdctsf_2 = "100002f7R-R",
666 | efdctuiz_2 = "100002f8R-R",
667 | efdctsiz_2 = "100002faR-R",
668 | efdtstgt_3 = "100002fcXRR",
669 | efdtstgt_2 = "100002fc-RR",
670 | efdtstlt_3 = "100002fdXRR",
671 | efdtstlt_2 = "100002fd-RR",
672 | efdtsteq_3 = "100002feXRR",
673 | efdtsteq_2 = "100002fe-RR",
674 | evlddx_3 = "10000300RR0R",
675 | evldd_2 = "10000301R8",
676 | evldwx_3 = "10000302RR0R",
677 | evldw_2 = "10000303R8",
678 | evldhx_3 = "10000304RR0R",
679 | evldh_2 = "10000305R8",
680 | evlwhex_3 = "10000310RR0R",
681 | evlwhe_2 = "10000311R4",
682 | evlwhoux_3 = "10000314RR0R",
683 | evlwhou_2 = "10000315R4",
684 | evlwhosx_3 = "10000316RR0R",
685 | evlwhos_2 = "10000317R4",
686 | evstddx_3 = "10000320RR0R",
687 | evstdd_2 = "10000321R8",
688 | evstdwx_3 = "10000322RR0R",
689 | evstdw_2 = "10000323R8",
690 | evstdhx_3 = "10000324RR0R",
691 | evstdh_2 = "10000325R8",
692 | evstwhex_3 = "10000330RR0R",
693 | evstwhe_2 = "10000331R4",
694 | evstwhox_3 = "10000334RR0R",
695 | evstwho_2 = "10000335R4",
696 | evstwwex_3 = "10000338RR0R",
697 | evstwwe_2 = "10000339R4",
698 | evstwwox_3 = "1000033cRR0R",
699 | evstwwo_2 = "1000033dR4",
700 | evmhessf_3 = "10000403RRR",
701 | evmhossf_3 = "10000407RRR",
702 | evmheumi_3 = "10000408RRR",
703 | evmhesmi_3 = "10000409RRR",
704 | evmhesmf_3 = "1000040bRRR",
705 | evmhoumi_3 = "1000040cRRR",
706 | evmhosmi_3 = "1000040dRRR",
707 | evmhosmf_3 = "1000040fRRR",
708 | evmhessfa_3 = "10000423RRR",
709 | evmhossfa_3 = "10000427RRR",
710 | evmheumia_3 = "10000428RRR",
711 | evmhesmia_3 = "10000429RRR",
712 | evmhesmfa_3 = "1000042bRRR",
713 | evmhoumia_3 = "1000042cRRR",
714 | evmhosmia_3 = "1000042dRRR",
715 | evmhosmfa_3 = "1000042fRRR",
716 | evmwhssf_3 = "10000447RRR",
717 | evmwlumi_3 = "10000448RRR",
718 | evmwhumi_3 = "1000044cRRR",
719 | evmwhsmi_3 = "1000044dRRR",
720 | evmwhsmf_3 = "1000044fRRR",
721 | evmwssf_3 = "10000453RRR",
722 | evmwumi_3 = "10000458RRR",
723 | evmwsmi_3 = "10000459RRR",
724 | evmwsmf_3 = "1000045bRRR",
725 | evmwhssfa_3 = "10000467RRR",
726 | evmwlumia_3 = "10000468RRR",
727 | evmwhumia_3 = "1000046cRRR",
728 | evmwhsmia_3 = "1000046dRRR",
729 | evmwhsmfa_3 = "1000046fRRR",
730 | evmwssfa_3 = "10000473RRR",
731 | evmwumia_3 = "10000478RRR",
732 | evmwsmia_3 = "10000479RRR",
733 | evmwsmfa_3 = "1000047bRRR",
734 | evmra_2 = "100004c4RR",
735 | evdivws_3 = "100004c6RRR",
736 | evdivwu_3 = "100004c7RRR",
737 | evmwssfaa_3 = "10000553RRR",
738 | evmwumiaa_3 = "10000558RRR",
739 | evmwsmiaa_3 = "10000559RRR",
740 | evmwsmfaa_3 = "1000055bRRR",
741 | evmwssfan_3 = "100005d3RRR",
742 | evmwumian_3 = "100005d8RRR",
743 | evmwsmian_3 = "100005d9RRR",
744 | evmwsmfan_3 = "100005dbRRR",
745 | evmergehilo_3 = "1000022eRRR",
746 | evmergelohi_3 = "1000022fRRR",
747 | evlhhesplatx_3 = "10000308RR0R",
748 | evlhhesplat_2 = "10000309R2",
749 | evlhhousplatx_3 = "1000030cRR0R",
750 | evlhhousplat_2 = "1000030dR2",
751 | evlhhossplatx_3 = "1000030eRR0R",
752 | evlhhossplat_2 = "1000030fR2",
753 | evlwwsplatx_3 = "10000318RR0R",
754 | evlwwsplat_2 = "10000319R4",
755 | evlwhsplatx_3 = "1000031cRR0R",
756 | evlwhsplat_2 = "1000031dR4",
757 | evaddusiaaw_2 = "100004c0RR",
758 | evaddssiaaw_2 = "100004c1RR",
759 | evsubfusiaaw_2 = "100004c2RR",
760 | evsubfssiaaw_2 = "100004c3RR",
761 | evaddumiaaw_2 = "100004c8RR",
762 | evaddsmiaaw_2 = "100004c9RR",
763 | evsubfumiaaw_2 = "100004caRR",
764 | evsubfsmiaaw_2 = "100004cbRR",
765 | evmheusiaaw_3 = "10000500RRR",
766 | evmhessiaaw_3 = "10000501RRR",
767 | evmhessfaaw_3 = "10000503RRR",
768 | evmhousiaaw_3 = "10000504RRR",
769 | evmhossiaaw_3 = "10000505RRR",
770 | evmhossfaaw_3 = "10000507RRR",
771 | evmheumiaaw_3 = "10000508RRR",
772 | evmhesmiaaw_3 = "10000509RRR",
773 | evmhesmfaaw_3 = "1000050bRRR",
774 | evmhoumiaaw_3 = "1000050cRRR",
775 | evmhosmiaaw_3 = "1000050dRRR",
776 | evmhosmfaaw_3 = "1000050fRRR",
777 | evmhegumiaa_3 = "10000528RRR",
778 | evmhegsmiaa_3 = "10000529RRR",
779 | evmhegsmfaa_3 = "1000052bRRR",
780 | evmhogumiaa_3 = "1000052cRRR",
781 | evmhogsmiaa_3 = "1000052dRRR",
782 | evmhogsmfaa_3 = "1000052fRRR",
783 | evmwlusiaaw_3 = "10000540RRR",
784 | evmwlssiaaw_3 = "10000541RRR",
785 | evmwlumiaaw_3 = "10000548RRR",
786 | evmwlsmiaaw_3 = "10000549RRR",
787 | evmheusianw_3 = "10000580RRR",
788 | evmhessianw_3 = "10000581RRR",
789 | evmhessfanw_3 = "10000583RRR",
790 | evmhousianw_3 = "10000584RRR",
791 | evmhossianw_3 = "10000585RRR",
792 | evmhossfanw_3 = "10000587RRR",
793 | evmheumianw_3 = "10000588RRR",
794 | evmhesmianw_3 = "10000589RRR",
795 | evmhesmfanw_3 = "1000058bRRR",
796 | evmhoumianw_3 = "1000058cRRR",
797 | evmhosmianw_3 = "1000058dRRR",
798 | evmhosmfanw_3 = "1000058fRRR",
799 | evmhegumian_3 = "100005a8RRR",
800 | evmhegsmian_3 = "100005a9RRR",
801 | evmhegsmfan_3 = "100005abRRR",
802 | evmhogumian_3 = "100005acRRR",
803 | evmhogsmian_3 = "100005adRRR",
804 | evmhogsmfan_3 = "100005afRRR",
805 | evmwlusianw_3 = "100005c0RRR",
806 | evmwlssianw_3 = "100005c1RRR",
807 | evmwlumianw_3 = "100005c8RRR",
808 | evmwlsmianw_3 = "100005c9RRR",
809 |
810 | -- NYI: some 64 bit PowerPC and Book E instructions:
811 | -- rldicl, rldicr, rldic, rldimi, rldcl, rldcr, sradi, 64 bit ext. add/sub,
812 | -- extended addressing branches, cache management, loads and stores
813 | }
814 |
815 | -- Add mnemonics for "." variants.
816 | do
817 | local t = {}
818 | for k,v in pairs(map_op) do
819 | if sub(v, -1) == "." then
820 | local v2 = sub(v, 1, 7)..char(byte(v, 8)+1)..sub(v, 9, -2)
821 | t[sub(k, 1, -3).."."..sub(k, -2)] = v2
822 | end
823 | end
824 | for k,v in pairs(t) do
825 | map_op[k] = v
826 | end
827 | end
828 |
829 | -- Add more branch mnemonics.
830 | for cond,c in pairs(map_cond) do
831 | local b1 = "b"..cond
832 | local c1 = (c%4)*0x00010000 + (c < 4 and 0x01000000 or 0)
833 | -- bX[l]
834 | map_op[b1.."_1"] = tohex(0x40800000 + c1).."K"
835 | map_op[b1.."y_1"] = tohex(0x40a00000 + c1).."K"
836 | map_op[b1.."l_1"] = tohex(0x40800001 + c1).."K"
837 | map_op[b1.."_2"] = tohex(0x40800000 + c1).."-XK"
838 | map_op[b1.."y_2"] = tohex(0x40a00000 + c1).."-XK"
839 | map_op[b1.."l_2"] = tohex(0x40800001 + c1).."-XK"
840 | -- bXlr[l]
841 | map_op[b1.."lr_0"] = tohex(0x4c800020 + c1)
842 | map_op[b1.."lrl_0"] = tohex(0x4c800021 + c1)
843 | map_op[b1.."ctr_0"] = tohex(0x4c800420 + c1)
844 | map_op[b1.."ctrl_0"] = tohex(0x4c800421 + c1)
845 | -- bXctr[l]
846 | map_op[b1.."lr_1"] = tohex(0x4c800020 + c1).."-X"
847 | map_op[b1.."lrl_1"] = tohex(0x4c800021 + c1).."-X"
848 | map_op[b1.."ctr_1"] = tohex(0x4c800420 + c1).."-X"
849 | map_op[b1.."ctrl_1"] = tohex(0x4c800421 + c1).."-X"
850 | end
851 |
852 | ------------------------------------------------------------------------------
853 |
854 | local function parse_gpr(expr)
855 | local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$")
856 | local tp = map_type[tname or expr]
857 | if tp then
858 | local reg = ovreg or tp.reg
859 | if not reg then
860 | werror("type `"..(tname or expr).."' needs a register override")
861 | end
862 | expr = reg
863 | end
864 | local r = match(expr, "^r([1-3]?[0-9])$")
865 | if r then
866 | r = tonumber(r)
867 | if r <= 31 then return r, tp end
868 | end
869 | werror("bad register name `"..expr.."'")
870 | end
871 |
872 | local function parse_fpr(expr)
873 | local r = match(expr, "^f([1-3]?[0-9])$")
874 | if r then
875 | r = tonumber(r)
876 | if r <= 31 then return r end
877 | end
878 | werror("bad register name `"..expr.."'")
879 | end
880 |
881 | local function parse_cr(expr)
882 | local r = match(expr, "^cr([0-7])$")
883 | if r then return tonumber(r) end
884 | werror("bad condition register name `"..expr.."'")
885 | end
886 |
887 | local function parse_cond(expr)
888 | local r, cond = match(expr, "^4%*cr([0-7])%+(%w%w)$")
889 | if r then
890 | r = tonumber(r)
891 | local c = map_cond[cond]
892 | if c and c < 4 then return r*4+c end
893 | end
894 | werror("bad condition bit name `"..expr.."'")
895 | end
896 |
897 | local function parse_imm(imm, bits, shift, scale, signed)
898 | local n = tonumber(imm)
899 | if n then
900 | if n % 2^scale == 0 then
901 | n = n / 2^scale
902 | if signed then
903 | if n >= 0 then
904 | if n < 2^(bits-1) then return n*2^shift end
905 | else
906 | if n >= -(2^(bits-1))-1 then return (n+2^bits)*2^shift end
907 | end
908 | else
909 | if n >= 0 and n <= 2^bits-1 then return n*2^shift end
910 | end
911 | end
912 | werror("out of range immediate `"..imm.."'")
913 | elseif match(imm, "^r([1-3]?[0-9])$") or
914 | match(imm, "^([%w_]+):(r[1-3]?[0-9])$") then
915 | werror("expected immediate operand, got register")
916 | else
917 | waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm)
918 | return 0
919 | end
920 | end
921 |
922 | local function parse_disp(disp)
923 | local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$")
924 | if imm then
925 | local r = parse_gpr(reg)
926 | if r == 0 then werror("cannot use r0 in displacement") end
927 | return r*65536 + parse_imm(imm, 16, 0, 0, true)
928 | end
929 | local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$")
930 | if reg and tailr ~= "" then
931 | local r, tp = parse_gpr(reg)
932 | if r == 0 then werror("cannot use r0 in displacement") end
933 | if tp then
934 | waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr))
935 | return r*65536
936 | end
937 | end
938 | werror("bad displacement `"..disp.."'")
939 | end
940 |
941 | local function parse_u5disp(disp, scale)
942 | local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$")
943 | if imm then
944 | local r = parse_gpr(reg)
945 | if r == 0 then werror("cannot use r0 in displacement") end
946 | return r*65536 + parse_imm(imm, 5, 11, scale, false)
947 | end
948 | local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$")
949 | if reg and tailr ~= "" then
950 | local r, tp = parse_gpr(reg)
951 | if r == 0 then werror("cannot use r0 in displacement") end
952 | if tp then
953 | waction("IMM", scale*1024+5*32+11, format(tp.ctypefmt, tailr))
954 | return r*65536
955 | end
956 | end
957 | werror("bad displacement `"..disp.."'")
958 | end
959 |
960 | local function parse_label(label, def)
961 | local prefix = sub(label, 1, 2)
962 | -- =>label (pc label reference)
963 | if prefix == "=>" then
964 | return "PC", 0, sub(label, 3)
965 | end
966 | -- ->name (global label reference)
967 | if prefix == "->" then
968 | return "LG", map_global[sub(label, 3)]
969 | end
970 | if def then
971 | -- [1-9] (local label definition)
972 | if match(label, "^[1-9]$") then
973 | return "LG", 10+tonumber(label)
974 | end
975 | else
976 | -- [<>][1-9] (local label reference)
977 | local dir, lnum = match(label, "^([<>])([1-9])$")
978 | if dir then -- Fwd: 1-9, Bkwd: 11-19.
979 | return "LG", lnum + (dir == ">" and 0 or 10)
980 | end
981 | -- extern label (extern label reference)
982 | local extname = match(label, "^extern%s+(%S+)$")
983 | if extname then
984 | return "EXT", map_extern[extname]
985 | end
986 | end
987 | werror("bad label `"..label.."'")
988 | end
989 |
990 | ------------------------------------------------------------------------------
991 |
992 | -- Handle opcodes defined with template strings.
993 | map_op[".template__"] = function(params, template, nparams)
994 | if not params then return sub(template, 9) end
995 | local op = tonumber(sub(template, 1, 8), 16)
996 | local n, rs = 1, 26
997 |
998 | -- Limit number of section buffer positions used by a single dasm_put().
999 | -- A single opcode needs a maximum of 3 positions (rlwinm).
1000 | if secpos+3 > maxsecpos then wflush() end
1001 | local pos = wpos()
1002 |
1003 | -- Process each character.
1004 | for p in gmatch(sub(template, 9), ".") do
1005 | if p == "R" then
1006 | rs = rs - 5; op = op + parse_gpr(params[n]) * 2^rs; n = n + 1
1007 | elseif p == "F" then
1008 | rs = rs - 5; op = op + parse_fpr(params[n]) * 2^rs; n = n + 1
1009 | elseif p == "A" then
1010 | rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, false); n = n + 1
1011 | elseif p == "S" then
1012 | rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, true); n = n + 1
1013 | elseif p == "I" then
1014 | op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1
1015 | elseif p == "U" then
1016 | op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1
1017 | elseif p == "D" then
1018 | op = op + parse_disp(params[n]); n = n + 1
1019 | elseif p == "2" then
1020 | op = op + parse_u5disp(params[n], 1); n = n + 1
1021 | elseif p == "4" then
1022 | op = op + parse_u5disp(params[n], 2); n = n + 1
1023 | elseif p == "8" then
1024 | op = op + parse_u5disp(params[n], 3); n = n + 1
1025 | elseif p == "C" then
1026 | rs = rs - 5; op = op + parse_cond(params[n]) * 2^rs; n = n + 1
1027 | elseif p == "X" then
1028 | rs = rs - 5; op = op + parse_cr(params[n]) * 2^(rs+2); n = n + 1
1029 | elseif p == "W" then
1030 | op = op + parse_cr(params[n]); n = n + 1
1031 | elseif p == "G" then
1032 | op = op + parse_imm(params[n], 8, 12, 0, false); n = n + 1
1033 | elseif p == "J" or p == "K" then
1034 | local mode, n, s = parse_label(params[n], false)
1035 | if p == "K" then n = n + 2048 end
1036 | waction("REL_"..mode, n, s, 1)
1037 | n = n + 1
1038 | elseif p == "0" then
1039 | local mm = 2^rs
1040 | local t = op % mm
1041 | if ((op - t) / mm) % 32 == 0 then werror("cannot use r0") end
1042 | elseif p == "=" or p == "%" then
1043 | local mm = 2^(rs + (p == "%" and 5 or 0))
1044 | local t = ((op - op % mm) / mm) % 32
1045 | rs = rs - 5
1046 | op = op + t * 2^rs
1047 | elseif p == "~" then
1048 | local mm = 2^rs
1049 | local t1l = op % mm
1050 | local t1h = (op - t1l) / mm
1051 | local t2l = t1h % 32
1052 | local t2h = (t1h - t2l) / 32
1053 | local t3l = t2h % 32
1054 | op = ((t2h - t3l + t2l)*32 + t3l)*mm + t1l
1055 | elseif p == "-" then
1056 | rs = rs - 5
1057 | elseif p == "." then
1058 | -- Ignored.
1059 | else
1060 | assert(false)
1061 | end
1062 | end
1063 | wputpos(pos, op)
1064 | end
1065 |
1066 | ------------------------------------------------------------------------------
1067 |
1068 | -- Pseudo-opcode to mark the position where the action list is to be emitted.
1069 | map_op[".actionlist_1"] = function(params)
1070 | if not params then return "cvar" end
1071 | local name = params[1] -- No syntax check. You get to keep the pieces.
1072 | wline(function(out) writeactions(out, name) end)
1073 | end
1074 |
1075 | -- Pseudo-opcode to mark the position where the global enum is to be emitted.
1076 | map_op[".globals_1"] = function(params)
1077 | if not params then return "prefix" end
1078 | local prefix = params[1] -- No syntax check. You get to keep the pieces.
1079 | wline(function(out) writeglobals(out, prefix) end)
1080 | end
1081 |
1082 | -- Pseudo-opcode to mark the position where the global names are to be emitted.
1083 | map_op[".globalnames_1"] = function(params)
1084 | if not params then return "cvar" end
1085 | local name = params[1] -- No syntax check. You get to keep the pieces.
1086 | wline(function(out) writeglobalnames(out, name) end)
1087 | end
1088 |
1089 | -- Pseudo-opcode to mark the position where the extern names are to be emitted.
1090 | map_op[".externnames_1"] = function(params)
1091 | if not params then return "cvar" end
1092 | local name = params[1] -- No syntax check. You get to keep the pieces.
1093 | wline(function(out) writeexternnames(out, name) end)
1094 | end
1095 |
1096 | ------------------------------------------------------------------------------
1097 |
1098 | -- Label pseudo-opcode (converted from trailing colon form).
1099 | map_op[".label_1"] = function(params)
1100 | if not params then return "[1-9] | ->global | =>pcexpr" end
1101 | if secpos+1 > maxsecpos then wflush() end
1102 | local mode, n, s = parse_label(params[1], true)
1103 | if mode == "EXT" then werror("bad label definition") end
1104 | waction("LABEL_"..mode, n, s, 1)
1105 | end
1106 |
1107 | ------------------------------------------------------------------------------
1108 |
1109 | -- Pseudo-opcodes for data storage.
1110 | map_op[".long_*"] = function(params)
1111 | if not params then return "imm..." end
1112 | for _,p in ipairs(params) do
1113 | local n = tonumber(p)
1114 | if not n then werror("bad immediate `"..p.."'") end
1115 | if n < 0 then n = n + 2^32 end
1116 | wputw(n)
1117 | if secpos+2 > maxsecpos then wflush() end
1118 | end
1119 | end
1120 |
1121 | -- Alignment pseudo-opcode.
1122 | map_op[".align_1"] = function(params)
1123 | if not params then return "numpow2" end
1124 | if secpos+1 > maxsecpos then wflush() end
1125 | local align = tonumber(params[1])
1126 | if align then
1127 | local x = align
1128 | -- Must be a power of 2 in the range (2 ... 256).
1129 | for i=1,8 do
1130 | x = x / 2
1131 | if x == 1 then
1132 | waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1.
1133 | return
1134 | end
1135 | end
1136 | end
1137 | werror("bad alignment")
1138 | end
1139 |
1140 | ------------------------------------------------------------------------------
1141 |
1142 | -- Pseudo-opcode for (primitive) type definitions (map to C types).
1143 | map_op[".type_3"] = function(params, nparams)
1144 | if not params then
1145 | return nparams == 2 and "name, ctype" or "name, ctype, reg"
1146 | end
1147 | local name, ctype, reg = params[1], params[2], params[3]
1148 | if not match(name, "^[%a_][%w_]*$") then
1149 | werror("bad type name `"..name.."'")
1150 | end
1151 | local tp = map_type[name]
1152 | if tp then
1153 | werror("duplicate type `"..name.."'")
1154 | end
1155 | -- Add #type to defines. A bit unclean to put it in map_archdef.
1156 | map_archdef["#"..name] = "sizeof("..ctype..")"
1157 | -- Add new type and emit shortcut define.
1158 | local num = ctypenum + 1
1159 | map_type[name] = {
1160 | ctype = ctype,
1161 | ctypefmt = format("Dt%X(%%s)", num),
1162 | reg = reg,
1163 | }
1164 | wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
1165 | ctypenum = num
1166 | end
1167 | map_op[".type_2"] = map_op[".type_3"]
1168 |
1169 | -- Dump type definitions.
1170 | local function dumptypes(out, lvl)
1171 | local t = {}
1172 | for name in pairs(map_type) do t[#t+1] = name end
1173 | sort(t)
1174 | out:write("Type definitions:\n")
1175 | for _,name in ipairs(t) do
1176 | local tp = map_type[name]
1177 | local reg = tp.reg or ""
1178 | out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
1179 | end
1180 | out:write("\n")
1181 | end
1182 |
1183 | ------------------------------------------------------------------------------
1184 |
1185 | -- Set the current section.
1186 | function _M.section(num)
1187 | waction("SECTION", num)
1188 | wflush(true) -- SECTION is a terminal action.
1189 | end
1190 |
1191 | ------------------------------------------------------------------------------
1192 |
1193 | -- Dump architecture description.
1194 | function _M.dumparch(out)
1195 | out:write(format("DynASM %s version %s, released %s\n\n",
1196 | _info.arch, _info.version, _info.release))
1197 | dumpactions(out)
1198 | end
1199 |
1200 | -- Dump all user defined elements.
1201 | function _M.dumpdef(out, lvl)
1202 | dumptypes(out, lvl)
1203 | dumpglobals(out, lvl)
1204 | dumpexterns(out, lvl)
1205 | end
1206 |
1207 | ------------------------------------------------------------------------------
1208 |
1209 | -- Pass callbacks from/to the DynASM core.
1210 | function _M.passcb(wl, we, wf, ww)
1211 | wline, werror, wfatal, wwarn = wl, we, wf, ww
1212 | return wflush
1213 | end
1214 |
1215 | -- Setup the arch-specific module.
1216 | function _M.setup(arch, opt)
1217 | g_arch, g_opt = arch, opt
1218 | end
1219 |
1220 | -- Merge the core maps and the arch-specific maps.
1221 | function _M.mergemaps(map_coreop, map_def)
1222 | setmetatable(map_op, { __index = map_coreop })
1223 | setmetatable(map_def, { __index = map_archdef })
1224 | return map_op, map_def
1225 | end
1226 |
1227 | return _M
1228 |
1229 | ------------------------------------------------------------------------------
1230 |
1231 |
--------------------------------------------------------------------------------
/third_party/dynasm/dasm_proto.h:
--------------------------------------------------------------------------------
1 | /*
2 | ** DynASM encoding engine prototypes.
3 | ** Copyright (C) 2005-2012 Mike Pall. All rights reserved.
4 | ** Released under the MIT license. See dynasm.lua for full copyright notice.
5 | */
6 |
7 | #ifndef _DASM_PROTO_H
8 | #define _DASM_PROTO_H
9 |
10 | #include
11 | #include
12 |
13 | #define DASM_IDENT "DynASM 1.3.0"
14 | #define DASM_VERSION 10300 /* 1.3.0 */
15 |
16 | #ifndef Dst_DECL
17 | #define Dst_DECL dasm_State **Dst
18 | #endif
19 |
20 | #ifndef Dst_REF
21 | #define Dst_REF (*Dst)
22 | #endif
23 |
24 | #ifndef DASM_FDEF
25 | #define DASM_FDEF extern
26 | #endif
27 |
28 | #ifndef DASM_M_GROW
29 | #define DASM_M_GROW(ctx, t, p, sz, need) \
30 | do { \
31 | size_t _sz = (sz), _need = (need); \
32 | if (_sz < _need) { \
33 | if (_sz < 16) _sz = 16; \
34 | while (_sz < _need) _sz += _sz; \
35 | (p) = (t *)realloc((p), _sz); \
36 | if ((p) == NULL) exit(1); \
37 | (sz) = _sz; \
38 | } \
39 | } while(0)
40 | #endif
41 |
42 | #ifndef DASM_M_FREE
43 | #define DASM_M_FREE(ctx, p, sz) free(p)
44 | #endif
45 |
46 | /* Internal DynASM encoder state. */
47 | typedef struct dasm_State dasm_State;
48 |
49 |
50 | /* Initialize and free DynASM state. */
51 | DASM_FDEF void dasm_init(Dst_DECL, int maxsection);
52 | DASM_FDEF void dasm_free(Dst_DECL);
53 |
54 | /* Setup global array. Must be called before dasm_setup(). */
55 | DASM_FDEF void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl);
56 |
57 | /* Grow PC label array. Can be called after dasm_setup(), too. */
58 | DASM_FDEF void dasm_growpc(Dst_DECL, unsigned int maxpc);
59 |
60 | /* Setup encoder. */
61 | DASM_FDEF void dasm_setup(Dst_DECL, const void *actionlist);
62 |
63 | /* Feed encoder with actions. Calls are generated by pre-processor. */
64 | DASM_FDEF void dasm_put(Dst_DECL, int start, ...);
65 |
66 | /* Link sections and return the resulting size. */
67 | DASM_FDEF int dasm_link(Dst_DECL, size_t *szp);
68 |
69 | /* Encode sections into buffer. */
70 | DASM_FDEF int dasm_encode(Dst_DECL, void *buffer);
71 |
72 | /* Get PC label offset. */
73 | DASM_FDEF int dasm_getpclabel(Dst_DECL, unsigned int pc);
74 |
75 | #ifdef DASM_CHECKS
76 | /* Optional sanity checker to call between isolated encoding steps. */
77 | DASM_FDEF int dasm_checkstep(Dst_DECL, int secmatch);
78 | #else
79 | #define dasm_checkstep(a, b) 0
80 | #endif
81 |
82 |
83 | #endif /* _DASM_PROTO_H */
84 |
--------------------------------------------------------------------------------
/third_party/dynasm/dasm_x64.lua:
--------------------------------------------------------------------------------
1 | ------------------------------------------------------------------------------
2 | -- DynASM x64 module.
3 | --
4 | -- Copyright (C) 2005-2012 Mike Pall. All rights reserved.
5 | -- See dynasm.lua for full copyright notice.
6 | ------------------------------------------------------------------------------
7 | -- This module just sets 64 bit mode for the combined x86/x64 module.
8 | -- All the interesting stuff is there.
9 | ------------------------------------------------------------------------------
10 |
11 | x64 = true -- Using a global is an ugly, but effective solution.
12 | return require("dasm_x86")
13 |
--------------------------------------------------------------------------------
/third_party/dynasm/dasm_x86.h:
--------------------------------------------------------------------------------
1 | /*
2 | ** DynASM x86 encoding engine.
3 | ** Copyright (C) 2005-2012 Mike Pall. All rights reserved.
4 | ** Released under the MIT license. See dynasm.lua for full copyright notice.
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #define DASM_ARCH "x86"
13 |
14 | #ifndef DASM_EXTERN
15 | #define DASM_EXTERN(a,b,c,d) 0
16 | #endif
17 |
18 | /* Action definitions. DASM_STOP must be 255. */
19 | enum {
20 | DASM_DISP = 233,
21 | DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB,
22 | DASM_VREG, DASM_SPACE, DASM_SETLABEL, DASM_REL_A, DASM_REL_LG, DASM_REL_PC,
23 | DASM_IMM_LG, DASM_IMM_PC, DASM_LABEL_LG, DASM_LABEL_PC, DASM_ALIGN,
24 | DASM_EXTERN, DASM_ESC, DASM_MARK, DASM_SECTION, DASM_STOP
25 | };
26 |
27 | /* Maximum number of section buffer positions for a single dasm_put() call. */
28 | #define DASM_MAXSECPOS 25
29 |
30 | /* DynASM encoder status codes. Action list offset or number are or'ed in. */
31 | #define DASM_S_OK 0x00000000
32 | #define DASM_S_NOMEM 0x01000000
33 | #define DASM_S_PHASE 0x02000000
34 | #define DASM_S_MATCH_SEC 0x03000000
35 | #define DASM_S_RANGE_I 0x11000000
36 | #define DASM_S_RANGE_SEC 0x12000000
37 | #define DASM_S_RANGE_LG 0x13000000
38 | #define DASM_S_RANGE_PC 0x14000000
39 | #define DASM_S_RANGE_VREG 0x15000000
40 | #define DASM_S_UNDEF_L 0x21000000
41 | #define DASM_S_UNDEF_PC 0x22000000
42 |
43 | /* Macros to convert positions (8 bit section + 24 bit index). */
44 | #define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
45 | #define DASM_POS2BIAS(pos) ((pos)&0xff000000)
46 | #define DASM_SEC2POS(sec) ((sec)<<24)
47 | #define DASM_POS2SEC(pos) ((pos)>>24)
48 | #define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
49 |
50 | /* Action list type. */
51 | typedef const unsigned char *dasm_ActList;
52 |
53 | /* Per-section structure. */
54 | typedef struct dasm_Section {
55 | int *rbuf; /* Biased buffer pointer (negative section bias). */
56 | int *buf; /* True buffer pointer. */
57 | size_t bsize; /* Buffer size in bytes. */
58 | int pos; /* Biased buffer position. */
59 | int epos; /* End of biased buffer position - max single put. */
60 | int ofs; /* Byte offset into section. */
61 | } dasm_Section;
62 |
63 | /* Core structure holding the DynASM encoding state. */
64 | struct dasm_State {
65 | size_t psize; /* Allocated size of this structure. */
66 | dasm_ActList actionlist; /* Current actionlist pointer. */
67 | int *lglabels; /* Local/global chain/pos ptrs. */
68 | size_t lgsize;
69 | int *pclabels; /* PC label chains/pos ptrs. */
70 | size_t pcsize;
71 | void **globals; /* Array of globals (bias -10). */
72 | dasm_Section *section; /* Pointer to active section. */
73 | size_t codesize; /* Total size of all code sections. */
74 | int maxsection; /* 0 <= sectionidx < maxsection. */
75 | int status; /* Status code. */
76 | dasm_Section sections[1]; /* All sections. Alloc-extended. */
77 | };
78 |
79 | /* The size of the core structure depends on the max. number of sections. */
80 | #define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
81 |
82 |
83 | /* Initialize DynASM state. */
84 | void dasm_init(Dst_DECL, int maxsection)
85 | {
86 | dasm_State *D;
87 | size_t psz = 0;
88 | int i;
89 | Dst_REF = NULL;
90 | DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
91 | D = Dst_REF;
92 | D->psize = psz;
93 | D->lglabels = NULL;
94 | D->lgsize = 0;
95 | D->pclabels = NULL;
96 | D->pcsize = 0;
97 | D->globals = NULL;
98 | D->maxsection = maxsection;
99 | for (i = 0; i < maxsection; i++) {
100 | D->sections[i].buf = NULL; /* Need this for pass3. */
101 | D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
102 | D->sections[i].bsize = 0;
103 | D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
104 | }
105 | }
106 |
107 | /* Free DynASM state. */
108 | void dasm_free(Dst_DECL)
109 | {
110 | dasm_State *D = Dst_REF;
111 | int i;
112 | for (i = 0; i < D->maxsection; i++)
113 | if (D->sections[i].buf)
114 | DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
115 | if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
116 | if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
117 | DASM_M_FREE(Dst, D, D->psize);
118 | }
119 |
120 | /* Setup global label array. Must be called before dasm_setup(). */
121 | void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
122 | {
123 | dasm_State *D = Dst_REF;
124 | D->globals = gl - 10; /* Negative bias to compensate for locals. */
125 | DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
126 | }
127 |
128 | /* Grow PC label array. Can be called after dasm_setup(), too. */
129 | void dasm_growpc(Dst_DECL, unsigned int maxpc)
130 | {
131 | dasm_State *D = Dst_REF;
132 | size_t osz = D->pcsize;
133 | DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
134 | memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
135 | }
136 |
137 | /* Setup encoder. */
138 | void dasm_setup(Dst_DECL, const void *actionlist)
139 | {
140 | dasm_State *D = Dst_REF;
141 | int i;
142 | D->actionlist = (dasm_ActList)actionlist;
143 | D->status = DASM_S_OK;
144 | D->section = &D->sections[0];
145 | memset((void *)D->lglabels, 0, D->lgsize);
146 | if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
147 | for (i = 0; i < D->maxsection; i++) {
148 | D->sections[i].pos = DASM_SEC2POS(i);
149 | D->sections[i].ofs = 0;
150 | }
151 | }
152 |
153 |
154 | #ifdef DASM_CHECKS
155 | #define CK(x, st) \
156 | do { if (!(x)) { \
157 | D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0)
158 | #define CKPL(kind, st) \
159 | do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
160 | D->status=DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0)
161 | #else
162 | #define CK(x, st) ((void)0)
163 | #define CKPL(kind, st) ((void)0)
164 | #endif
165 |
166 | /* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
167 | void dasm_put(Dst_DECL, int start, ...)
168 | {
169 | va_list ap;
170 | dasm_State *D = Dst_REF;
171 | dasm_ActList p = D->actionlist + start;
172 | dasm_Section *sec = D->section;
173 | int pos = sec->pos, ofs = sec->ofs, mrm = 4;
174 | int *b;
175 |
176 | if (pos >= sec->epos) {
177 | DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
178 | sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
179 | sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
180 | sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
181 | }
182 |
183 | b = sec->rbuf;
184 | b[pos++] = start;
185 |
186 | va_start(ap, start);
187 | while (1) {
188 | int action = *p++;
189 | if (action < DASM_DISP) {
190 | ofs++;
191 | } else if (action <= DASM_REL_A) {
192 | int n = va_arg(ap, int);
193 | b[pos++] = n;
194 | switch (action) {
195 | case DASM_DISP:
196 | if (n == 0) { if ((mrm&7) == 4) mrm = p[-2]; if ((mrm&7) != 5) break; }
197 | case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob;
198 | case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */
199 | case DASM_IMM_D: ofs += 4; break;
200 | case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob;
201 | case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break;
202 | case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob;
203 | case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break;
204 | case DASM_SPACE: p++; ofs += n; break;
205 | case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */
206 | case DASM_VREG: CK((n&-8) == 0 && (n != 4 || (*p&1) == 0), RANGE_VREG);
207 | if (*p++ == 1 && *p == DASM_DISP) mrm = n; continue;
208 | }
209 | mrm = 4;
210 | } else {
211 | int *pl, n;
212 | switch (action) {
213 | case DASM_REL_LG:
214 | case DASM_IMM_LG:
215 | n = *p++; pl = D->lglabels + n;
216 | if (n <= 246) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */
217 | pl -= 246; n = *pl;
218 | if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
219 | goto linkrel;
220 | case DASM_REL_PC:
221 | case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
222 | putrel:
223 | n = *pl;
224 | if (n < 0) { /* Label exists. Get label pos and store it. */
225 | b[pos] = -n;
226 | } else {
227 | linkrel:
228 | b[pos] = n; /* Else link to rel chain, anchored at label. */
229 | *pl = pos;
230 | }
231 | pos++;
232 | ofs += 4; /* Maximum offset needed. */
233 | if (action == DASM_REL_LG || action == DASM_REL_PC)
234 | b[pos++] = ofs; /* Store pass1 offset estimate. */
235 | break;
236 | case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel;
237 | case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
238 | putlabel:
239 | n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
240 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; }
241 | *pl = -pos; /* Label exists now. */
242 | b[pos++] = ofs; /* Store pass1 offset estimate. */
243 | break;
244 | case DASM_ALIGN:
245 | ofs += *p++; /* Maximum alignment needed (arg is 2**n-1). */
246 | b[pos++] = ofs; /* Store pass1 offset estimate. */
247 | break;
248 | case DASM_EXTERN: p += 2; ofs += 4; break;
249 | case DASM_ESC: p++; ofs++; break;
250 | case DASM_MARK: mrm = p[-2]; break;
251 | case DASM_SECTION:
252 | n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n];
253 | case DASM_STOP: goto stop;
254 | }
255 | }
256 | }
257 | stop:
258 | va_end(ap);
259 | sec->pos = pos;
260 | sec->ofs = ofs;
261 | }
262 | #undef CK
263 |
264 | /* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */
265 | int dasm_link(Dst_DECL, size_t *szp)
266 | {
267 | dasm_State *D = Dst_REF;
268 | int secnum;
269 | int ofs = 0;
270 |
271 | #ifdef DASM_CHECKS
272 | *szp = 0;
273 | if (D->status != DASM_S_OK) return D->status;
274 | {
275 | int pc;
276 | for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
277 | if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
278 | }
279 | #endif
280 |
281 | { /* Handle globals not defined in this translation unit. */
282 | int idx;
283 | for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) {
284 | int n = D->lglabels[idx];
285 | /* Undefined label: Collapse rel chain and replace with marker (< 0). */
286 | while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
287 | }
288 | }
289 |
290 | /* Combine all code sections. No support for data sections (yet). */
291 | for (secnum = 0; secnum < D->maxsection; secnum++) {
292 | dasm_Section *sec = D->sections + secnum;
293 | int *b = sec->rbuf;
294 | int pos = DASM_SEC2POS(secnum);
295 | int lastpos = sec->pos;
296 |
297 | while (pos != lastpos) {
298 | dasm_ActList p = D->actionlist + b[pos++];
299 | while (1) {
300 | int op, action = *p++;
301 | switch (action) {
302 | case DASM_REL_LG: p++; op = p[-3]; goto rel_pc;
303 | case DASM_REL_PC: op = p[-2]; rel_pc: {
304 | int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0);
305 | if (shrink) { /* Shrinkable branch opcode? */
306 | int lofs, lpos = b[pos];
307 | if (lpos < 0) goto noshrink; /* Ext global? */
308 | lofs = *DASM_POS2PTR(D, lpos);
309 | if (lpos > pos) { /* Fwd label: add cumulative section offsets. */
310 | int i;
311 | for (i = secnum; i < DASM_POS2SEC(lpos); i++)
312 | lofs += D->sections[i].ofs;
313 | } else {
314 | lofs -= ofs; /* Bkwd label: unfix offset. */
315 | }
316 | lofs -= b[pos+1]; /* Short branch ok? */
317 | if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink; /* Yes. */
318 | else { noshrink: shrink = 0; } /* No, cannot shrink op. */
319 | }
320 | b[pos+1] = shrink;
321 | pos += 2;
322 | break;
323 | }
324 | case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++;
325 | case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W:
326 | case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB:
327 | case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break;
328 | case DASM_LABEL_LG: p++;
329 | case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */
330 | case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */
331 | case DASM_EXTERN: p += 2; break;
332 | case DASM_ESC: p++; break;
333 | case DASM_MARK: break;
334 | case DASM_SECTION: case DASM_STOP: goto stop;
335 | }
336 | }
337 | stop: (void)0;
338 | }
339 | ofs += sec->ofs; /* Next section starts right after current section. */
340 | }
341 |
342 | D->codesize = ofs; /* Total size of all code sections */
343 | *szp = ofs;
344 | return DASM_S_OK;
345 | }
346 |
347 | #define dasmb(x) *cp++ = (unsigned char)(x)
348 | #ifndef DASM_ALIGNED_WRITES
349 | #define dasmw(x) \
350 | do { *((unsigned short *)cp) = (unsigned short)(x); cp+=2; } while (0)
351 | #define dasmd(x) \
352 | do { *((unsigned int *)cp) = (unsigned int)(x); cp+=4; } while (0)
353 | #else
354 | #define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0)
355 | #define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0)
356 | #endif
357 |
358 | /* Pass 3: Encode sections. */
359 | int dasm_encode(Dst_DECL, void *buffer)
360 | {
361 | dasm_State *D = Dst_REF;
362 | unsigned char *base = (unsigned char *)buffer;
363 | unsigned char *cp = base;
364 | int secnum;
365 |
366 | /* Encode all code sections. No support for data sections (yet). */
367 | for (secnum = 0; secnum < D->maxsection; secnum++) {
368 | dasm_Section *sec = D->sections + secnum;
369 | int *b = sec->buf;
370 | int *endb = sec->rbuf + sec->pos;
371 |
372 | while (b != endb) {
373 | dasm_ActList p = D->actionlist + *b++;
374 | unsigned char *mark = NULL;
375 | while (1) {
376 | int action = *p++;
377 | int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0;
378 | switch (action) {
379 | case DASM_DISP: if (!mark) mark = cp; {
380 | unsigned char *mm = mark;
381 | if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL;
382 | if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7;
383 | if (mrm != 5) { mm[-1] -= 0x80; break; } }
384 | if (((n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40;
385 | }
386 | case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break;
387 | case DASM_IMM_DB: if (((n+128)&-256) == 0) {
388 | db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb;
389 | } else mark = NULL;
390 | case DASM_IMM_D: wd: dasmd(n); break;
391 | case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL;
392 | case DASM_IMM_W: dasmw(n); break;
393 | case DASM_VREG: { int t = *p++; if (t >= 2) n<<=3; cp[-1] |= n; break; }
394 | case DASM_REL_LG: p++; if (n >= 0) goto rel_pc;
395 | b++; n = (int)(ptrdiff_t)D->globals[-n];
396 | case DASM_REL_A: rel_a: n -= (int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */
397 | case DASM_REL_PC: rel_pc: {
398 | int shrink = *b++;
399 | int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; }
400 | n = *pb - ((int)(cp-base) + 4-shrink);
401 | if (shrink == 0) goto wd;
402 | if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb;
403 | goto wb;
404 | }
405 | case DASM_IMM_LG:
406 | p++; if (n < 0) { n = (int)(ptrdiff_t)D->globals[-n]; goto wd; }
407 | case DASM_IMM_PC: {
408 | int *pb = DASM_POS2PTR(D, n);
409 | n = *pb < 0 ? pb[1] : (*pb + (int)(ptrdiff_t)base);
410 | goto wd;
411 | }
412 | case DASM_LABEL_LG: {
413 | int idx = *p++;
414 | if (idx >= 10)
415 | D->globals[idx] = (void *)(base + (*p == DASM_SETLABEL ? *b : n));
416 | break;
417 | }
418 | case DASM_LABEL_PC: case DASM_SETLABEL: break;
419 | case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; }
420 | case DASM_ALIGN:
421 | n = *p++;
422 | while (((cp-base) & n)) *cp++ = 0x90; /* nop */
423 | break;
424 | case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd;
425 | case DASM_MARK: mark = cp; break;
426 | case DASM_ESC: action = *p++;
427 | default: *cp++ = action; break;
428 | case DASM_SECTION: case DASM_STOP: goto stop;
429 | }
430 | }
431 | stop: (void)0;
432 | }
433 | }
434 |
435 | if (base + D->codesize != cp) /* Check for phase errors. */
436 | return DASM_S_PHASE;
437 | return DASM_S_OK;
438 | }
439 |
440 | /* Get PC label offset. */
441 | int dasm_getpclabel(Dst_DECL, unsigned int pc)
442 | {
443 | dasm_State *D = Dst_REF;
444 | if (pc*sizeof(int) < D->pcsize) {
445 | int pos = D->pclabels[pc];
446 | if (pos < 0) return *DASM_POS2PTR(D, -pos);
447 | if (pos > 0) return -1; /* Undefined. */
448 | }
449 | return -2; /* Unused or out of range. */
450 | }
451 |
452 | #ifdef DASM_CHECKS
453 | /* Optional sanity checker to call between isolated encoding steps. */
454 | int dasm_checkstep(Dst_DECL, int secmatch)
455 | {
456 | dasm_State *D = Dst_REF;
457 | if (D->status == DASM_S_OK) {
458 | int i;
459 | for (i = 1; i <= 9; i++) {
460 | if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; }
461 | D->lglabels[i] = 0;
462 | }
463 | }
464 | if (D->status == DASM_S_OK && secmatch >= 0 &&
465 | D->section != &D->sections[secmatch])
466 | D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections);
467 | return D->status;
468 | }
469 | #endif
470 |
471 |
--------------------------------------------------------------------------------
/third_party/dynasm/dynasm.lua:
--------------------------------------------------------------------------------
1 | ------------------------------------------------------------------------------
2 | -- DynASM. A dynamic assembler for code generation engines.
3 | -- Originally designed and implemented for LuaJIT.
4 | --
5 | -- Copyright (C) 2005-2012 Mike Pall. All rights reserved.
6 | -- See below for full copyright notice.
7 | ------------------------------------------------------------------------------
8 |
9 | -- Application information.
10 | local _info = {
11 | name = "DynASM",
12 | description = "A dynamic assembler for code generation engines",
13 | version = "1.3.0",
14 | vernum = 10300,
15 | release = "2011-05-05",
16 | author = "Mike Pall",
17 | url = "http://luajit.org/dynasm.html",
18 | license = "MIT",
19 | copyright = [[
20 | Copyright (C) 2005-2012 Mike Pall. All rights reserved.
21 |
22 | Permission is hereby granted, free of charge, to any person obtaining
23 | a copy of this software and associated documentation files (the
24 | "Software"), to deal in the Software without restriction, including
25 | without limitation the rights to use, copy, modify, merge, publish,
26 | distribute, sublicense, and/or sell copies of the Software, and to
27 | permit persons to whom the Software is furnished to do so, subject to
28 | the following conditions:
29 |
30 | The above copyright notice and this permission notice shall be
31 | included in all copies or substantial portions of the Software.
32 |
33 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
34 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
35 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
36 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
37 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
38 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
39 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 |
41 | [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
42 | ]],
43 | }
44 |
45 | -- Cache library functions.
46 | local type, pairs, ipairs = type, pairs, ipairs
47 | local pcall, error, assert = pcall, error, assert
48 | local _s = string
49 | local sub, match, gmatch, gsub = _s.sub, _s.match, _s.gmatch, _s.gsub
50 | local format, rep, upper = _s.format, _s.rep, _s.upper
51 | local _t = table
52 | local insert, remove, concat, sort = _t.insert, _t.remove, _t.concat, _t.sort
53 | local exit = os.exit
54 | local io = io
55 | local stdin, stdout, stderr = io.stdin, io.stdout, io.stderr
56 |
57 | ------------------------------------------------------------------------------
58 |
59 | -- Program options.
60 | local g_opt = {}
61 |
62 | -- Global state for current file.
63 | local g_fname, g_curline, g_indent, g_lineno, g_synclineno, g_arch
64 | local g_errcount = 0
65 |
66 | -- Write buffer for output file.
67 | local g_wbuffer, g_capbuffer
68 |
69 | ------------------------------------------------------------------------------
70 |
71 | -- Write an output line (or callback function) to the buffer.
72 | local function wline(line, needindent)
73 | local buf = g_capbuffer or g_wbuffer
74 | buf[#buf+1] = needindent and g_indent..line or line
75 | g_synclineno = g_synclineno + 1
76 | end
77 |
78 | -- Write assembler line as a comment, if requestd.
79 | local function wcomment(aline)
80 | if g_opt.comment then
81 | wline(g_opt.comment..aline..g_opt.endcomment, true)
82 | end
83 | end
84 |
85 | -- Resync CPP line numbers.
86 | local function wsync()
87 | if g_synclineno ~= g_lineno and g_opt.cpp then
88 | wline("# "..g_lineno..' "'..g_fname..'"')
89 | g_synclineno = g_lineno
90 | end
91 | end
92 |
93 | -- Dummy action flush function. Replaced with arch-specific function later.
94 | local function wflush(term)
95 | end
96 |
97 | -- Dump all buffered output lines.
98 | local function wdumplines(out, buf)
99 | for _,line in ipairs(buf) do
100 | if type(line) == "string" then
101 | assert(out:write(line, "\n"))
102 | else
103 | -- Special callback to dynamically insert lines after end of processing.
104 | line(out)
105 | end
106 | end
107 | end
108 |
109 | ------------------------------------------------------------------------------
110 |
111 | -- Emit an error. Processing continues with next statement.
112 | local function werror(msg)
113 | error(format("%s:%s: error: %s:\n%s", g_fname, g_lineno, msg, g_curline), 0)
114 | end
115 |
116 | -- Emit a fatal error. Processing stops.
117 | local function wfatal(msg)
118 | g_errcount = "fatal"
119 | werror(msg)
120 | end
121 |
122 | -- Print a warning. Processing continues.
123 | local function wwarn(msg)
124 | stderr:write(format("%s:%s: warning: %s:\n%s\n",
125 | g_fname, g_lineno, msg, g_curline))
126 | end
127 |
128 | -- Print caught error message. But suppress excessive errors.
129 | local function wprinterr(...)
130 | if type(g_errcount) == "number" then
131 | -- Regular error.
132 | g_errcount = g_errcount + 1
133 | if g_errcount < 21 then -- Seems to be a reasonable limit.
134 | stderr:write(...)
135 | elseif g_errcount == 21 then
136 | stderr:write(g_fname,
137 | ":*: warning: too many errors (suppressed further messages).\n")
138 | end
139 | else
140 | -- Fatal error.
141 | stderr:write(...)
142 | return true -- Stop processing.
143 | end
144 | end
145 |
146 | ------------------------------------------------------------------------------
147 |
148 | -- Map holding all option handlers.
149 | local opt_map = {}
150 | local opt_current
151 |
152 | -- Print error and exit with error status.
153 | local function opterror(...)
154 | stderr:write("dynasm.lua: ERROR: ", ...)
155 | stderr:write("\n")
156 | exit(1)
157 | end
158 |
159 | -- Get option parameter.
160 | local function optparam(args)
161 | local argn = args.argn
162 | local p = args[argn]
163 | if not p then
164 | opterror("missing parameter for option `", opt_current, "'.")
165 | end
166 | args.argn = argn + 1
167 | return p
168 | end
169 |
170 | ------------------------------------------------------------------------------
171 |
172 | -- Core pseudo-opcodes.
173 | local map_coreop = {}
174 | -- Dummy opcode map. Replaced by arch-specific map.
175 | local map_op = {}
176 |
177 | -- Forward declarations.
178 | local dostmt
179 | local readfile
180 |
181 | ------------------------------------------------------------------------------
182 |
183 | -- Map for defines (initially empty, chains to arch-specific map).
184 | local map_def = {}
185 |
186 | -- Pseudo-opcode to define a substitution.
187 | map_coreop[".define_2"] = function(params, nparams)
188 | if not params then return nparams == 1 and "name" or "name, subst" end
189 | local name, def = params[1], params[2] or "1"
190 | if not match(name, "^[%a_][%w_]*$") then werror("bad or duplicate define") end
191 | map_def[name] = def
192 | end
193 | map_coreop[".define_1"] = map_coreop[".define_2"]
194 |
195 | -- Define a substitution on the command line.
196 | function opt_map.D(args)
197 | local namesubst = optparam(args)
198 | local name, subst = match(namesubst, "^([%a_][%w_]*)=(.*)$")
199 | if name then
200 | map_def[name] = subst
201 | elseif match(namesubst, "^[%a_][%w_]*$") then
202 | map_def[namesubst] = "1"
203 | else
204 | opterror("bad define")
205 | end
206 | end
207 |
208 | -- Undefine a substitution on the command line.
209 | function opt_map.U(args)
210 | local name = optparam(args)
211 | if match(name, "^[%a_][%w_]*$") then
212 | map_def[name] = nil
213 | else
214 | opterror("bad define")
215 | end
216 | end
217 |
218 | -- Helper for definesubst.
219 | local gotsubst
220 |
221 | local function definesubst_one(word)
222 | local subst = map_def[word]
223 | if subst then gotsubst = word; return subst else return word end
224 | end
225 |
226 | -- Iteratively substitute defines.
227 | local function definesubst(stmt)
228 | -- Limit number of iterations.
229 | for i=1,100 do
230 | gotsubst = false
231 | stmt = gsub(stmt, "#?[%w_]+", definesubst_one)
232 | if not gotsubst then break end
233 | end
234 | if gotsubst then wfatal("recursive define involving `"..gotsubst.."'") end
235 | return stmt
236 | end
237 |
238 | -- Dump all defines.
239 | local function dumpdefines(out, lvl)
240 | local t = {}
241 | for name in pairs(map_def) do
242 | t[#t+1] = name
243 | end
244 | sort(t)
245 | out:write("Defines:\n")
246 | for _,name in ipairs(t) do
247 | local subst = map_def[name]
248 | if g_arch then subst = g_arch.revdef(subst) end
249 | out:write(format(" %-20s %s\n", name, subst))
250 | end
251 | out:write("\n")
252 | end
253 |
254 | ------------------------------------------------------------------------------
255 |
256 | -- Support variables for conditional assembly.
257 | local condlevel = 0
258 | local condstack = {}
259 |
260 | -- Evaluate condition with a Lua expression. Substitutions already performed.
261 | local function cond_eval(cond)
262 | local func, err
263 | if setfenv then
264 | func, err = loadstring("return "..cond, "=expr")
265 | else
266 | -- No globals. All unknown identifiers evaluate to nil.
267 | func, err = load("return "..cond, "=expr", "t", {})
268 | end
269 | if func then
270 | if setfenv then
271 | setfenv(func, {}) -- No globals. All unknown identifiers evaluate to nil.
272 | end
273 | local ok, res = pcall(func)
274 | if ok then
275 | if res == 0 then return false end -- Oh well.
276 | return not not res
277 | end
278 | err = res
279 | end
280 | wfatal("bad condition: "..err)
281 | end
282 |
283 | -- Skip statements until next conditional pseudo-opcode at the same level.
284 | local function stmtskip()
285 | local dostmt_save = dostmt
286 | local lvl = 0
287 | dostmt = function(stmt)
288 | local op = match(stmt, "^%s*(%S+)")
289 | if op == ".if" then
290 | lvl = lvl + 1
291 | elseif lvl ~= 0 then
292 | if op == ".endif" then lvl = lvl - 1 end
293 | elseif op == ".elif" or op == ".else" or op == ".endif" then
294 | dostmt = dostmt_save
295 | dostmt(stmt)
296 | end
297 | end
298 | end
299 |
300 | -- Pseudo-opcodes for conditional assembly.
301 | map_coreop[".if_1"] = function(params)
302 | if not params then return "condition" end
303 | local lvl = condlevel + 1
304 | local res = cond_eval(params[1])
305 | condlevel = lvl
306 | condstack[lvl] = res
307 | if not res then stmtskip() end
308 | end
309 |
310 | map_coreop[".elif_1"] = function(params)
311 | if not params then return "condition" end
312 | if condlevel == 0 then wfatal(".elif without .if") end
313 | local lvl = condlevel
314 | local res = condstack[lvl]
315 | if res then
316 | if res == "else" then wfatal(".elif after .else") end
317 | else
318 | res = cond_eval(params[1])
319 | if res then
320 | condstack[lvl] = res
321 | return
322 | end
323 | end
324 | stmtskip()
325 | end
326 |
327 | map_coreop[".else_0"] = function(params)
328 | if condlevel == 0 then wfatal(".else without .if") end
329 | local lvl = condlevel
330 | local res = condstack[lvl]
331 | condstack[lvl] = "else"
332 | if res then
333 | if res == "else" then wfatal(".else after .else") end
334 | stmtskip()
335 | end
336 | end
337 |
338 | map_coreop[".endif_0"] = function(params)
339 | local lvl = condlevel
340 | if lvl == 0 then wfatal(".endif without .if") end
341 | condlevel = lvl - 1
342 | end
343 |
344 | -- Check for unfinished conditionals.
345 | local function checkconds()
346 | if g_errcount ~= "fatal" and condlevel ~= 0 then
347 | wprinterr(g_fname, ":*: error: unbalanced conditional\n")
348 | end
349 | end
350 |
351 | ------------------------------------------------------------------------------
352 |
353 | -- Search for a file in the given path and open it for reading.
354 | local function pathopen(path, name)
355 | local dirsep = match(package.path, "\\") and "\\" or "/"
356 | for _,p in ipairs(path) do
357 | local fullname = p == "" and name or p..dirsep..name
358 | local fin = io.open(fullname, "r")
359 | if fin then
360 | g_fname = fullname
361 | return fin
362 | end
363 | end
364 | end
365 |
366 | -- Include a file.
367 | map_coreop[".include_1"] = function(params)
368 | if not params then return "filename" end
369 | local name = params[1]
370 | -- Save state. Ugly, I know. but upvalues are fast.
371 | local gf, gl, gcl, gi = g_fname, g_lineno, g_curline, g_indent
372 | -- Read the included file.
373 | local fatal = readfile(pathopen(g_opt.include, name) or
374 | wfatal("include file `"..name.."' not found"))
375 | -- Restore state.
376 | g_synclineno = -1
377 | g_fname, g_lineno, g_curline, g_indent = gf, gl, gcl, gi
378 | if fatal then wfatal("in include file") end
379 | end
380 |
381 | -- Make .include and conditionals initially available, too.
382 | map_op[".include_1"] = map_coreop[".include_1"]
383 | map_op[".if_1"] = map_coreop[".if_1"]
384 | map_op[".elif_1"] = map_coreop[".elif_1"]
385 | map_op[".else_0"] = map_coreop[".else_0"]
386 | map_op[".endif_0"] = map_coreop[".endif_0"]
387 |
388 | ------------------------------------------------------------------------------
389 |
390 | -- Support variables for macros.
391 | local mac_capture, mac_lineno, mac_name
392 | local mac_active = {}
393 | local mac_list = {}
394 |
395 | -- Pseudo-opcode to define a macro.
396 | map_coreop[".macro_*"] = function(mparams)
397 | if not mparams then return "name [, params...]" end
398 | -- Split off and validate macro name.
399 | local name = remove(mparams, 1)
400 | if not name then werror("missing macro name") end
401 | if not (match(name, "^[%a_][%w_%.]*$") or match(name, "^%.[%w_%.]*$")) then
402 | wfatal("bad macro name `"..name.."'")
403 | end
404 | -- Validate macro parameter names.
405 | local mdup = {}
406 | for _,mp in ipairs(mparams) do
407 | if not match(mp, "^[%a_][%w_]*$") then
408 | wfatal("bad macro parameter name `"..mp.."'")
409 | end
410 | if mdup[mp] then wfatal("duplicate macro parameter name `"..mp.."'") end
411 | mdup[mp] = true
412 | end
413 | -- Check for duplicate or recursive macro definitions.
414 | local opname = name.."_"..#mparams
415 | if map_op[opname] or map_op[name.."_*"] then
416 | wfatal("duplicate macro `"..name.."' ("..#mparams.." parameters)")
417 | end
418 | if mac_capture then wfatal("recursive macro definition") end
419 |
420 | -- Enable statement capture.
421 | local lines = {}
422 | mac_lineno = g_lineno
423 | mac_name = name
424 | mac_capture = function(stmt) -- Statement capture function.
425 | -- Stop macro definition with .endmacro pseudo-opcode.
426 | if not match(stmt, "^%s*.endmacro%s*$") then
427 | lines[#lines+1] = stmt
428 | return
429 | end
430 | mac_capture = nil
431 | mac_lineno = nil
432 | mac_name = nil
433 | mac_list[#mac_list+1] = opname
434 | -- Add macro-op definition.
435 | map_op[opname] = function(params)
436 | if not params then return mparams, lines end
437 | -- Protect against recursive macro invocation.
438 | if mac_active[opname] then wfatal("recursive macro invocation") end
439 | mac_active[opname] = true
440 | -- Setup substitution map.
441 | local subst = {}
442 | for i,mp in ipairs(mparams) do subst[mp] = params[i] end
443 | local mcom
444 | if g_opt.maccomment and g_opt.comment then
445 | mcom = " MACRO "..name.." ("..#mparams..")"
446 | wcomment("{"..mcom)
447 | end
448 | -- Loop through all captured statements
449 | for _,stmt in ipairs(lines) do
450 | -- Substitute macro parameters.
451 | local st = gsub(stmt, "[%w_]+", subst)
452 | st = definesubst(st)
453 | st = gsub(st, "%s*%.%.%s*", "") -- Token paste a..b.
454 | if mcom and sub(st, 1, 1) ~= "|" then wcomment(st) end
455 | -- Emit statement. Use a protected call for better diagnostics.
456 | local ok, err = pcall(dostmt, st)
457 | if not ok then
458 | -- Add the captured statement to the error.
459 | wprinterr(err, "\n", g_indent, "| ", stmt,
460 | "\t[MACRO ", name, " (", #mparams, ")]\n")
461 | end
462 | end
463 | if mcom then wcomment("}"..mcom) end
464 | mac_active[opname] = nil
465 | end
466 | end
467 | end
468 |
469 | -- An .endmacro pseudo-opcode outside of a macro definition is an error.
470 | map_coreop[".endmacro_0"] = function(params)
471 | wfatal(".endmacro without .macro")
472 | end
473 |
474 | -- Dump all macros and their contents (with -PP only).
475 | local function dumpmacros(out, lvl)
476 | sort(mac_list)
477 | out:write("Macros:\n")
478 | for _,opname in ipairs(mac_list) do
479 | local name = sub(opname, 1, -3)
480 | local params, lines = map_op[opname]()
481 | out:write(format(" %-20s %s\n", name, concat(params, ", ")))
482 | if lvl > 1 then
483 | for _,line in ipairs(lines) do
484 | out:write(" |", line, "\n")
485 | end
486 | out:write("\n")
487 | end
488 | end
489 | out:write("\n")
490 | end
491 |
492 | -- Check for unfinished macro definitions.
493 | local function checkmacros()
494 | if mac_capture then
495 | wprinterr(g_fname, ":", mac_lineno,
496 | ": error: unfinished .macro `", mac_name ,"'\n")
497 | end
498 | end
499 |
500 | ------------------------------------------------------------------------------
501 |
502 | -- Support variables for captures.
503 | local cap_lineno, cap_name
504 | local cap_buffers = {}
505 | local cap_used = {}
506 |
507 | -- Start a capture.
508 | map_coreop[".capture_1"] = function(params)
509 | if not params then return "name" end
510 | wflush()
511 | local name = params[1]
512 | if not match(name, "^[%a_][%w_]*$") then
513 | wfatal("bad capture name `"..name.."'")
514 | end
515 | if cap_name then
516 | wfatal("already capturing to `"..cap_name.."' since line "..cap_lineno)
517 | end
518 | cap_name = name
519 | cap_lineno = g_lineno
520 | -- Create or continue a capture buffer and start the output line capture.
521 | local buf = cap_buffers[name]
522 | if not buf then buf = {}; cap_buffers[name] = buf end
523 | g_capbuffer = buf
524 | g_synclineno = 0
525 | end
526 |
527 | -- Stop a capture.
528 | map_coreop[".endcapture_0"] = function(params)
529 | wflush()
530 | if not cap_name then wfatal(".endcapture without a valid .capture") end
531 | cap_name = nil
532 | cap_lineno = nil
533 | g_capbuffer = nil
534 | g_synclineno = 0
535 | end
536 |
537 | -- Dump a capture buffer.
538 | map_coreop[".dumpcapture_1"] = function(params)
539 | if not params then return "name" end
540 | wflush()
541 | local name = params[1]
542 | if not match(name, "^[%a_][%w_]*$") then
543 | wfatal("bad capture name `"..name.."'")
544 | end
545 | cap_used[name] = true
546 | wline(function(out)
547 | local buf = cap_buffers[name]
548 | if buf then wdumplines(out, buf) end
549 | end)
550 | g_synclineno = 0
551 | end
552 |
553 | -- Dump all captures and their buffers (with -PP only).
554 | local function dumpcaptures(out, lvl)
555 | out:write("Captures:\n")
556 | for name,buf in pairs(cap_buffers) do
557 | out:write(format(" %-20s %4s)\n", name, "("..#buf))
558 | if lvl > 1 then
559 | local bar = rep("=", 76)
560 | out:write(" ", bar, "\n")
561 | for _,line in ipairs(buf) do
562 | out:write(" ", line, "\n")
563 | end
564 | out:write(" ", bar, "\n\n")
565 | end
566 | end
567 | out:write("\n")
568 | end
569 |
570 | -- Check for unfinished or unused captures.
571 | local function checkcaptures()
572 | if cap_name then
573 | wprinterr(g_fname, ":", cap_lineno,
574 | ": error: unfinished .capture `", cap_name,"'\n")
575 | return
576 | end
577 | for name in pairs(cap_buffers) do
578 | if not cap_used[name] then
579 | wprinterr(g_fname, ":*: error: missing .dumpcapture ", name ,"\n")
580 | end
581 | end
582 | end
583 |
584 | ------------------------------------------------------------------------------
585 |
586 | -- Sections names.
587 | local map_sections = {}
588 |
589 | -- Pseudo-opcode to define code sections.
590 | -- TODO: Data sections, BSS sections. Needs extra C code and API.
591 | map_coreop[".section_*"] = function(params)
592 | if not params then return "name..." end
593 | if #map_sections > 0 then werror("duplicate section definition") end
594 | wflush()
595 | for sn,name in ipairs(params) do
596 | local opname = "."..name.."_0"
597 | if not match(name, "^[%a][%w_]*$") or
598 | map_op[opname] or map_op["."..name.."_*"] then
599 | werror("bad section name `"..name.."'")
600 | end
601 | map_sections[#map_sections+1] = name
602 | wline(format("#define DASM_SECTION_%s\t%d", upper(name), sn-1))
603 | map_op[opname] = function(params) g_arch.section(sn-1) end
604 | end
605 | wline(format("#define DASM_MAXSECTION\t\t%d", #map_sections))
606 | end
607 |
608 | -- Dump all sections.
609 | local function dumpsections(out, lvl)
610 | out:write("Sections:\n")
611 | for _,name in ipairs(map_sections) do
612 | out:write(format(" %s\n", name))
613 | end
614 | out:write("\n")
615 | end
616 |
617 | ------------------------------------------------------------------------------
618 |
619 | -- Load architecture-specific module.
620 | local function loadarch(arch)
621 | if not match(arch, "^[%w_]+$") then return "bad arch name" end
622 | local ok, m_arch = pcall(require, "dasm_"..arch)
623 | if not ok then return "cannot load module: "..m_arch end
624 | g_arch = m_arch
625 | wflush = m_arch.passcb(wline, werror, wfatal, wwarn)
626 | m_arch.setup(arch, g_opt)
627 | map_op, map_def = m_arch.mergemaps(map_coreop, map_def)
628 | end
629 |
630 | -- Dump architecture description.
631 | function opt_map.dumparch(args)
632 | local name = optparam(args)
633 | if not g_arch then
634 | local err = loadarch(name)
635 | if err then opterror(err) end
636 | end
637 |
638 | local t = {}
639 | for name in pairs(map_coreop) do t[#t+1] = name end
640 | for name in pairs(map_op) do t[#t+1] = name end
641 | sort(t)
642 |
643 | local out = stdout
644 | local _arch = g_arch._info
645 | out:write(format("%s version %s, released %s, %s\n",
646 | _info.name, _info.version, _info.release, _info.url))
647 | g_arch.dumparch(out)
648 |
649 | local pseudo = true
650 | out:write("Pseudo-Opcodes:\n")
651 | for _,sname in ipairs(t) do
652 | local name, nparam = match(sname, "^(.+)_([0-9%*])$")
653 | if name then
654 | if pseudo and sub(name, 1, 1) ~= "." then
655 | out:write("\nOpcodes:\n")
656 | pseudo = false
657 | end
658 | local f = map_op[sname]
659 | local s
660 | if nparam ~= "*" then nparam = nparam + 0 end
661 | if nparam == 0 then
662 | s = ""
663 | elseif type(f) == "string" then
664 | s = map_op[".template__"](nil, f, nparam)
665 | else
666 | s = f(nil, nparam)
667 | end
668 | if type(s) == "table" then
669 | for _,s2 in ipairs(s) do
670 | out:write(format(" %-12s %s\n", name, s2))
671 | end
672 | else
673 | out:write(format(" %-12s %s\n", name, s))
674 | end
675 | end
676 | end
677 | out:write("\n")
678 | exit(0)
679 | end
680 |
681 | -- Pseudo-opcode to set the architecture.
682 | -- Only initially available (map_op is replaced when called).
683 | map_op[".arch_1"] = function(params)
684 | if not params then return "name" end
685 | local err = loadarch(params[1])
686 | if err then wfatal(err) end
687 | end
688 |
689 | -- Dummy .arch pseudo-opcode to improve the error report.
690 | map_coreop[".arch_1"] = function(params)
691 | if not params then return "name" end
692 | wfatal("duplicate .arch statement")
693 | end
694 |
695 | ------------------------------------------------------------------------------
696 |
697 | -- Dummy pseudo-opcode. Don't confuse '.nop' with 'nop'.
698 | map_coreop[".nop_*"] = function(params)
699 | if not params then return "[ignored...]" end
700 | end
701 |
702 | -- Pseudo-opcodes to raise errors.
703 | map_coreop[".error_1"] = function(params)
704 | if not params then return "message" end
705 | werror(params[1])
706 | end
707 |
708 | map_coreop[".fatal_1"] = function(params)
709 | if not params then return "message" end
710 | wfatal(params[1])
711 | end
712 |
713 | -- Dump all user defined elements.
714 | local function dumpdef(out)
715 | local lvl = g_opt.dumpdef
716 | if lvl == 0 then return end
717 | dumpsections(out, lvl)
718 | dumpdefines(out, lvl)
719 | if g_arch then g_arch.dumpdef(out, lvl) end
720 | dumpmacros(out, lvl)
721 | dumpcaptures(out, lvl)
722 | end
723 |
724 | ------------------------------------------------------------------------------
725 |
726 | -- Helper for splitstmt.
727 | local splitlvl
728 |
729 | local function splitstmt_one(c)
730 | if c == "(" then
731 | splitlvl = ")"..splitlvl
732 | elseif c == "[" then
733 | splitlvl = "]"..splitlvl
734 | elseif c == "{" then
735 | splitlvl = "}"..splitlvl
736 | elseif c == ")" or c == "]" or c == "}" then
737 | if sub(splitlvl, 1, 1) ~= c then werror("unbalanced (), [] or {}") end
738 | splitlvl = sub(splitlvl, 2)
739 | elseif splitlvl == "" then
740 | return " \0 "
741 | end
742 | return c
743 | end
744 |
745 | -- Split statement into (pseudo-)opcode and params.
746 | local function splitstmt(stmt)
747 | -- Convert label with trailing-colon into .label statement.
748 | local label = match(stmt, "^%s*(.+):%s*$")
749 | if label then return ".label", {label} end
750 |
751 | -- Split at commas and equal signs, but obey parentheses and brackets.
752 | splitlvl = ""
753 | stmt = gsub(stmt, "[,%(%)%[%]{}]", splitstmt_one)
754 | if splitlvl ~= "" then werror("unbalanced () or []") end
755 |
756 | -- Split off opcode.
757 | local op, other = match(stmt, "^%s*([^%s%z]+)%s*(.*)$")
758 | if not op then werror("bad statement syntax") end
759 |
760 | -- Split parameters.
761 | local params = {}
762 | for p in gmatch(other, "%s*(%Z+)%z?") do
763 | params[#params+1] = gsub(p, "%s+$", "")
764 | end
765 | if #params > 16 then werror("too many parameters") end
766 |
767 | params.op = op
768 | return op, params
769 | end
770 |
771 | -- Process a single statement.
772 | dostmt = function(stmt)
773 | -- Ignore empty statements.
774 | if match(stmt, "^%s*$") then return end
775 |
776 | -- Capture macro defs before substitution.
777 | if mac_capture then return mac_capture(stmt) end
778 | stmt = definesubst(stmt)
779 |
780 | -- Emit C code without parsing the line.
781 | if sub(stmt, 1, 1) == "|" then
782 | local tail = sub(stmt, 2)
783 | wflush()
784 | if sub(tail, 1, 2) == "//" then wcomment(tail) else wline(tail, true) end
785 | return
786 | end
787 |
788 | -- Split into (pseudo-)opcode and params.
789 | local op, params = splitstmt(stmt)
790 |
791 | -- Get opcode handler (matching # of parameters or generic handler).
792 | local f = map_op[op.."_"..#params] or map_op[op.."_*"]
793 | if not f then
794 | if not g_arch then wfatal("first statement must be .arch") end
795 | -- Improve error report.
796 | for i=0,9 do
797 | if map_op[op.."_"..i] then
798 | werror("wrong number of parameters for `"..op.."'")
799 | end
800 | end
801 | werror("unknown statement `"..op.."'")
802 | end
803 |
804 | -- Call opcode handler or special handler for template strings.
805 | if type(f) == "string" then
806 | map_op[".template__"](params, f)
807 | else
808 | f(params)
809 | end
810 | end
811 |
812 | -- Process a single line.
813 | local function doline(line)
814 | if g_opt.flushline then wflush() end
815 |
816 | -- Assembler line?
817 | local indent, aline = match(line, "^(%s*)%|(.*)$")
818 | if not aline then
819 | -- No, plain C code line, need to flush first.
820 | wflush()
821 | wsync()
822 | wline(line, false)
823 | return
824 | end
825 |
826 | g_indent = indent -- Remember current line indentation.
827 |
828 | -- Emit C code (even from macros). Avoids echo and line parsing.
829 | if sub(aline, 1, 1) == "|" then
830 | if not mac_capture then
831 | wsync()
832 | elseif g_opt.comment then
833 | wsync()
834 | wcomment(aline)
835 | end
836 | dostmt(aline)
837 | return
838 | end
839 |
840 | -- Echo assembler line as a comment.
841 | if g_opt.comment then
842 | wsync()
843 | wcomment(aline)
844 | end
845 |
846 | -- Strip assembler comments.
847 | aline = gsub(aline, "//.*$", "")
848 |
849 | -- Split line into statements at semicolons.
850 | if match(aline, ";") then
851 | for stmt in gmatch(aline, "[^;]+") do dostmt(stmt) end
852 | else
853 | dostmt(aline)
854 | end
855 | end
856 |
857 | ------------------------------------------------------------------------------
858 |
859 | -- Write DynASM header.
860 | local function dasmhead(out)
861 | out:write(format([[
862 | /*
863 | ** This file has been pre-processed with DynASM.
864 | ** %s
865 | ** DynASM version %s, DynASM %s version %s
866 | ** DO NOT EDIT! The original file is in "%s".
867 | */
868 |
869 | #if DASM_VERSION != %d
870 | #error "Version mismatch between DynASM and included encoding engine"
871 | #endif
872 |
873 | ]], _info.url,
874 | _info.version, g_arch._info.arch, g_arch._info.version,
875 | g_fname, _info.vernum))
876 | end
877 |
878 | -- Read input file.
879 | readfile = function(fin)
880 | g_indent = ""
881 | g_lineno = 0
882 | g_synclineno = -1
883 |
884 | -- Process all lines.
885 | for line in fin:lines() do
886 | g_lineno = g_lineno + 1
887 | g_curline = line
888 | local ok, err = pcall(doline, line)
889 | if not ok and wprinterr(err, "\n") then return true end
890 | end
891 | wflush()
892 |
893 | -- Close input file.
894 | assert(fin == stdin or fin:close())
895 | end
896 |
897 | -- Write output file.
898 | local function writefile(outfile)
899 | local fout
900 |
901 | -- Open output file.
902 | if outfile == nil or outfile == "-" then
903 | fout = stdout
904 | else
905 | fout = assert(io.open(outfile, "w"))
906 | end
907 |
908 | -- Write all buffered lines
909 | wdumplines(fout, g_wbuffer)
910 |
911 | -- Close output file.
912 | assert(fout == stdout or fout:close())
913 |
914 | -- Optionally dump definitions.
915 | dumpdef(fout == stdout and stderr or stdout)
916 | end
917 |
918 | -- Translate an input file to an output file.
919 | local function translate(infile, outfile)
920 | g_wbuffer = {}
921 | g_indent = ""
922 | g_lineno = 0
923 | g_synclineno = -1
924 |
925 | -- Put header.
926 | wline(dasmhead)
927 |
928 | -- Read input file.
929 | local fin
930 | if infile == "-" then
931 | g_fname = "(stdin)"
932 | fin = stdin
933 | else
934 | g_fname = infile
935 | fin = assert(io.open(infile, "r"))
936 | end
937 | readfile(fin)
938 |
939 | -- Check for errors.
940 | if not g_arch then
941 | wprinterr(g_fname, ":*: error: missing .arch directive\n")
942 | end
943 | checkconds()
944 | checkmacros()
945 | checkcaptures()
946 |
947 | if g_errcount ~= 0 then
948 | stderr:write(g_fname, ":*: info: ", g_errcount, " error",
949 | (type(g_errcount) == "number" and g_errcount > 1) and "s" or "",
950 | " in input file -- no output file generated.\n")
951 | dumpdef(stderr)
952 | exit(1)
953 | end
954 |
955 | -- Write output file.
956 | writefile(outfile)
957 | end
958 |
959 | ------------------------------------------------------------------------------
960 |
961 | -- Print help text.
962 | function opt_map.help()
963 | stdout:write("DynASM -- ", _info.description, ".\n")
964 | stdout:write("DynASM ", _info.version, " ", _info.release, " ", _info.url, "\n")
965 | stdout:write[[
966 |
967 | Usage: dynasm [OPTION]... INFILE.dasc|-
968 |
969 | -h, --help Display this help text.
970 | -V, --version Display version and copyright information.
971 |
972 | -o, --outfile FILE Output file name (default is stdout).
973 | -I, --include DIR Add directory to the include search path.
974 |
975 | -c, --ccomment Use /* */ comments for assembler lines.
976 | -C, --cppcomment Use // comments for assembler lines (default).
977 | -N, --nocomment Suppress assembler lines in output.
978 | -M, --maccomment Show macro expansions as comments (default off).
979 |
980 | -L, --nolineno Suppress CPP line number information in output.
981 | -F, --flushline Flush action list for every line.
982 |
983 | -D NAME[=SUBST] Define a substitution.
984 | -U NAME Undefine a substitution.
985 |
986 | -P, --dumpdef Dump defines, macros, etc. Repeat for more output.
987 | -A, --dumparch ARCH Load architecture ARCH and dump description.
988 | ]]
989 | exit(0)
990 | end
991 |
992 | -- Print version information.
993 | function opt_map.version()
994 | stdout:write(format("%s version %s, released %s\n%s\n\n%s",
995 | _info.name, _info.version, _info.release, _info.url, _info.copyright))
996 | exit(0)
997 | end
998 |
999 | -- Misc. options.
1000 | function opt_map.outfile(args) g_opt.outfile = optparam(args) end
1001 | function opt_map.include(args) insert(g_opt.include, 1, optparam(args)) end
1002 | function opt_map.ccomment() g_opt.comment = "/*|"; g_opt.endcomment = " */" end
1003 | function opt_map.cppcomment() g_opt.comment = "//|"; g_opt.endcomment = "" end
1004 | function opt_map.nocomment() g_opt.comment = false end
1005 | function opt_map.maccomment() g_opt.maccomment = true end
1006 | function opt_map.nolineno() g_opt.cpp = false end
1007 | function opt_map.flushline() g_opt.flushline = true end
1008 | function opt_map.dumpdef() g_opt.dumpdef = g_opt.dumpdef + 1 end
1009 |
1010 | ------------------------------------------------------------------------------
1011 |
1012 | -- Short aliases for long options.
1013 | local opt_alias = {
1014 | h = "help", ["?"] = "help", V = "version",
1015 | o = "outfile", I = "include",
1016 | c = "ccomment", C = "cppcomment", N = "nocomment", M = "maccomment",
1017 | L = "nolineno", F = "flushline",
1018 | P = "dumpdef", A = "dumparch",
1019 | }
1020 |
1021 | -- Parse single option.
1022 | local function parseopt(opt, args)
1023 | opt_current = #opt == 1 and "-"..opt or "--"..opt
1024 | local f = opt_map[opt] or opt_map[opt_alias[opt]]
1025 | if not f then
1026 | opterror("unrecognized option `", opt_current, "'. Try `--help'.\n")
1027 | end
1028 | f(args)
1029 | end
1030 |
1031 | -- Parse arguments.
1032 | local function parseargs(args)
1033 | -- Default options.
1034 | g_opt.comment = "//|"
1035 | g_opt.endcomment = ""
1036 | g_opt.cpp = true
1037 | g_opt.dumpdef = 0
1038 | g_opt.include = { "" }
1039 |
1040 | -- Process all option arguments.
1041 | args.argn = 1
1042 | repeat
1043 | local a = args[args.argn]
1044 | if not a then break end
1045 | local lopt, opt = match(a, "^%-(%-?)(.+)")
1046 | if not opt then break end
1047 | args.argn = args.argn + 1
1048 | if lopt == "" then
1049 | -- Loop through short options.
1050 | for o in gmatch(opt, ".") do parseopt(o, args) end
1051 | else
1052 | -- Long option.
1053 | parseopt(opt, args)
1054 | end
1055 | until false
1056 |
1057 | -- Check for proper number of arguments.
1058 | local nargs = #args - args.argn + 1
1059 | if nargs ~= 1 then
1060 | if nargs == 0 then
1061 | if g_opt.dumpdef > 0 then return dumpdef(stdout) end
1062 | end
1063 | opt_map.help()
1064 | end
1065 |
1066 | -- Translate a single input file to a single output file
1067 | -- TODO: Handle multiple files?
1068 | translate(args[args.argn], g_opt.outfile)
1069 | end
1070 |
1071 | ------------------------------------------------------------------------------
1072 |
1073 | -- Add the directory dynasm.lua resides in to the Lua module search path.
1074 | local arg = arg
1075 | if arg and arg[0] then
1076 | local prefix = match(arg[0], "^(.*[/\\])")
1077 | if prefix then package.path = prefix.."?.lua;"..package.path end
1078 | end
1079 |
1080 | -- Start DynASM.
1081 | parseargs{...}
1082 |
1083 | ------------------------------------------------------------------------------
1084 |
1085 |
--------------------------------------------------------------------------------