1 // Assembly language support for x86_64 CPU.
2 // Bruno Haible 2016-12-28
3 
4 // Copyright (C) 1997-2021 Bruno Haible <bruno@clisp.org>
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
18 
19 // In order not to have to maintain several copies of the assembly language
20 // code, we use some macros which expand into the correct syntax.
21 // These macros are:
22 //   C(name)
23 //           This expands to the name of the C variable or function `name'.
24 //           On Unix BSD systems, this prepends an underscore.
25 //   L(label)
26 //           This expands to the name of a local label, having the name `label'.
27 //           On Unix ELF systems, where there is no underscore, names beginning
28 //           with an alphabetic character are automatically exported, so this
29 //           prepends a dot. Note that when defining a label, the `:' must
30 //           be inside the parentheses, not outside, because otherwise some
31 //           ANSI C preprocessor inserts a space between the label and the `:',
32 //           and some assemblers don't like this.
33 //   R(reg)
34 //           This expands to a reference to register `reg'. On Unix, this
35 //           prepends a % charater.
36 //   NUM(value)
37 //           This expands to an immediate value. On Unix, this prepends a $
38 //           character.
39 //   ADDR(variable)
40 //           This expands to an immediate value, the address of some variable
41 //           or function. On Unix, this prepends a $ character. With MSVC,
42 //           this prepends the keyword "OFFSET".
43 //   ADDR_PCRELATIVE(variable)
44 //           This expands to the address of symbol `variable', with program
45 //           counter (%rip) relative addressing.
46 //   About operand sizes: On Unix, a suffix to the instruction specifies the
47 //           size of the operands (for example "movb", "movw", "movl"). With
48 //           MSVC, there is no such suffix. Instead, the assembler infers the
49 //           operand size from the names of the registers ("al" vs. "ax" vs.
50 //           "eax"). This works well in most cases, but in instructions like
51 //           "mul [esi]" the assembler guesses the operand size: "byte" by
52 //           default. So it is better to explicitly specify the operand size
53 //           of memory operands (prefix X1, X2, X4, X8).
54 //           (Side note about Unix assemblers: Some Unix assemblers allow you
55 //           to write "testb %eax,%eax" but silently treat this as
56 //           "testb %al,%al".)
57 //   X1
58 //           This prefixes a memory reference of 1 byte.
59 //   X2
60 //           This prefixes a memory reference of 2 bytes.
61 //   X4
62 //           This prefixes a memory reference of 4 bytes.
63 //   X8
64 //           This prefixes a memory reference of 8 bytes.
65 //   MEM(base)
66 //           This expands to a memory reference at address `base'.
67 //   MEM_DISP(base,displacement)
68 //           This expands to a memory reference at address `base+displacement'.
69 //   MEM_INDEX(base,index)
70 //           This expands to a memory reference at address `base+index'.
71 //   MEM_SHINDEX(base,index,size)
72 //           This expands to a memory reference at address
73 //           `base+index*size', where `size' is 1, 2, 4, or 8.
74 //   MEM_DISP_SHINDEX0(displacement,index,size)
75 //           This expands to a memory reference at address
76 //           `displacement+index*size', where `size' is 1, 2, 4, or 8.
77 //   MEM_DISP_SHINDEX(base,displacement,index,size)
78 //           This expands to a memory reference at address
79 //           `base+displacement+index*size', where `size' is 1, 2, 4, or 8.
80 //   MEM_PCRELATIVE(variable)
81 //           This expands to a memory reference at symbol `variable', with
82 //           program counter (%rip) relative addressing.
83 //   INDIR(value)
84 //           This expands to an implicit indirection. On Unix, this prepends
85 //           a * character.
86 //   INSN1(mnemonic,size_suffix,dst)
87 //           This expands to an instruction with one operand.
88 //   INSN2(mnemonic,size_suffix,src,dst)
89 //           This expands to an instruction with two operands. In our notation,
90 //           `src' comes first and `dst' second, but they are reversed when
91 //           expanding to Intel syntax. In Intel syntax, size_suffix is omitted.
92 //   INSN2S(mnemonic,size_suffix,src,dst)
93 //           This expands to an instruction with two operands. In our notation,
94 //           `src' comes first and `dst' second, but they are reversed when
95 //           expanding to Intel syntax. In Intel syntax, size_suffix is
96 //           preserved.
97 //   INSN2MOVXL(mnemonic,size_suffix,src,dst)
98 //           This expands to an instruction with two operands, of type
99 //           movsbl/movzbl, which in some syntaxes requires a second suffix.
100 //   INSN2MOVXQ(mnemonic,size_suffix,src,dst)
101 //           This expands to an instruction with two operands, of type
102 //           movsbq/movzbq, which in some syntaxes requires a second suffix.
103 //   INSN2MOVXLQ(mnemonic,size_suffix,src,dst)
104 //           This expands to an instruction with two operands, of type
105 //           movslq/movzlq, which in some syntaxes requires a second suffix.
106 //   _
107 //           For instructions which don't have a size suffix, like jump
108 //           instructions. Expands to nothing. Needed for MSVC, which has
109 //           problems with empty macro arguments.
110 //   TEXT()
111 //           Switch to the code section.
112 //   P2ALIGN(log,max)
113 //           Align to 2^log bytes, but insert at most max bytes.
114 //   GLOBL(name)
115 //           Declare `name' to be a global symbol.
116 //   DECLARE_FUNCTION(name)
117 //           Declare `name' to be a global function. When assembly language
118 //           code is compiled into a shared library, ELF linkers need to know
119 //           which symbols are functions.
120 //   FUNBEGIN(name)
121 //           Start the assembly language code for the C function `name'.
122 //   FUNEND(name,size_expression)
123 //           End the assembly language code for the C function 'name'.
124 //   EH_FRAME_SECTION
125 //           The arguments to the .section statement that introduces the
126 //           exception handler section (on ELF platforms).
127 
128 #ifdef _MSC_VER
129 // MSVC
130 #define C(entrypoint) entrypoint
131 #define L(label) $L##label
132 #else
133 #ifdef ASM_UNDERSCORE
134 // Mac OS X
135 #define C(entrypoint) _##entrypoint
136 #define L(label) L##label
137 #else
138 // Linux/ELF, Solaris/ELF, Windows with GNU as
139 #define C(entrypoint) entrypoint
140 #define L(label) .L##label
141 #endif
142 #endif
143 
144 // The two syntaxes:
145 // - ATT_SYNTAX for GNU assembler version 2.
146 // - INTEL_SYNTAX for MS assembler.
147 // Note: INTEL_SYNTAX is not the same syntax as produced by "gcc masm=intel"
148 // as there are syntactic differences between that syntax and the one accepted
149 // by the MS assembler (for MEM_DISP, INDIR, P2ALIGN, FUNBEGIN, FUNEND etc.).
150 #ifdef _MSC_VER
151 // MS assembler
152 #define R(r) r
153 #define NUM(n) n
154 #define ADDR(a) OFFSET a
155 #define ADDR_PCRELATIVE(a) OFFSET a
156 #define X1 BYTE PTR
157 #define X2 WORD PTR
158 #define X4 DWORD PTR
159 #define X8 QWORD PTR
160 #define MEM(base) [base]
161 #define MEM_DISP(base,displacement) [base+(displacement)]
162 #define MEM_INDEX(base,index) [base+index]
163 #define MEM_SHINDEX(base,index,size) [base+index*size]
164 #define MEM_DISP_SHINDEX0(displacement,index,size) [(displacement)+index*size]
165 #define MEM_DISP_SHINDEX(base,displacement,index,size) [base+(displacement)+index*size]
166 #define MEM_PCRELATIVE(variable) variable
167 #define INDIR(value)value
168 #define INSNCONC(mnemonic,suffix)mnemonic##suffix
169 #define INSN1(mnemonic,size_suffix,dst)mnemonic dst
170 #define INSN2(mnemonic,size_suffix,src,dst)mnemonic dst,src
171 #define INSN2S(mnemonic,size_suffix,src,dst)INSNCONC(mnemonic,size_suffix) dst,src
172 #define INSN2MOVXL(mnemonic,size_suffix,src,dst)INSNCONC(mnemonic,x) dst,src
173 #define INSN2MOVXQ(mnemonic,size_suffix,src,dst)INSNCONC(mnemonic,x) dst,src
174 #define INSN2MOVXLQ(mnemonic,size_suffix,src,dst)INSNCONC(mnemonic,xd) dst,src
175 #else
176 // GNU assembler version 2
177 #define R(r) %r
178 #define NUM(n) $ n
179 #define ADDR(a) $##a
180 #define ADDR_PCRELATIVE(a) a(%rip)
181 #define X1
182 #define X2
183 #define X4
184 #define X8
185 #define MEM(base)(R(base))
186 #define MEM_DISP(base,displacement)displacement(R(base))
187 #define MEM_INDEX(base,index)(R(base),R(index))
188 #define MEM_SHINDEX(base,index,size)(R(base),R(index),size)
189 #define MEM_DISP_SHINDEX0(displacement,index,size)displacement(,R(index),size)
190 #define MEM_DISP_SHINDEX(base,displacement,index,size)displacement(R(base),R(index),size)
191 #define MEM_PCRELATIVE(variable) variable(%rip)
192 #define INDIR(value)*value
193 #define INSNCONC(mnemonic,size_suffix)mnemonic##size_suffix
194 #define INSN1(mnemonic,size_suffix,dst)INSNCONC(mnemonic,size_suffix) dst
195 #define INSN2(mnemonic,size_suffix,src,dst)INSNCONC(mnemonic,size_suffix) src,dst
196 #define INSN2S(mnemonic,size_suffix,src,dst)INSNCONC(mnemonic,size_suffix) src,dst
197 #define INSN2MOVXL(mnemonic,size_suffix,src,dst)INSNCONC(mnemonic,size_suffix##l) src,dst
198 #define INSN2MOVXQ(mnemonic,size_suffix,src,dst)INSNCONC(mnemonic,size_suffix##q) src,dst
199 #define INSN2MOVXLQ(mnemonic,size_suffix,src,dst)INSNCONC(mnemonic,size_suffix##q) src,dst
200 #endif
201 
202 #define _
203 
204 #ifdef _MSC_VER
205 // MS assembler
206 #define TEXT() _TEXT SEGMENT
207 #else
208 #define TEXT() .text
209 #endif
210 
211 #ifdef _MSC_VER
212 // MS assembler
213 // There is no equivalent for "p2align 4,,7". This comes closest:
214 #define P2ALIGN(log,max) ALIGN 8
215 #else
216 #if defined __sun
217 // Solaris
218 #define P2ALIGN(log,max) .align 1<<log
219 #else
220 // Mac OS X, Linux, Windows with GNU as
221 #define P2ALIGN(log,max) .p2align log,,max
222 #endif
223 #endif
224 
225 #ifdef _MSC_VER
226 // MS assembler
227 #define GLOBL(name)
228 #else
229 #define GLOBL(name) .globl name
230 #endif
231 
232 // Define the DECLARE_FUNCTION(name) macro.
233 #ifdef _MSC_VER
234 // MS assembler
235 #define DECLARE_FUNCTION(name) PUBLIC name
236 #else
237 #if defined _WIN32 || defined __CYGWIN__
238 // Windows with GNU as
239 #define DECLARE_FUNCTION(name) .def C(name); .scl 2; .type 32; .endef
240 #else
241 #ifdef ASM_UNDERSCORE
242 // Mac OS X
243 #define DECLARE_FUNCTION(name)
244 #else
245 // ELF
246 #define DECLARE_FUNCTION(name) .type C(name),@function
247 #endif
248 #endif
249 #endif
250 
251 // Define the FUNBEGIN(name) and FUNEND() macros.
252 #ifdef _MSC_VER
253 // MS assembler
254 #define FUNBEGIN(name) name PROC
255 #define FUNEND(name,size_expression) name ENDP
256 #else
257 #define FUNBEGIN(name) C(name):
258 #if (defined _WIN32 || defined __CYGWIN__) || defined(ASM_UNDERSCORE)
259 // Windows with GNU as, Mac OS X
260 #define FUNEND(name,size_expression)
261 #else
262 // ELF
263 #if defined __sun
264 // Solaris/ELF
265 #define FUNEND(name,size_expression) .size C(name), . - C(name)
266 #else
267 // Linux/ELF
268 #define FUNEND(name,size_expression) .size C(name),size_expression
269 #endif
270 #endif
271 #endif
272 
273 // Section of frame info for exception handlers
274 #if defined __APPLE__ && defined __MACH__
275 // Mac OS X
276 #define EH_FRAME_SECTION __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
277 #else
278 #if defined __sun
279 // Solaris/ELF
280 #define EH_FRAME_SECTION .eh_frame,"aL",link=.text,@unwind
281 #else
282 #if defined __FreeBSD__
283 // FreeBSD/ELF
284 #define EH_FRAME_SECTION .eh_frame,"a",@progbits
285 #else
286 // Linux/ELF
287 #define EH_FRAME_SECTION .eh_frame,"aw",@progbits
288 #endif
289 #endif
290 #endif
291