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