1 /* Jitter: patch-in header. 2 3 Copyright (C) 2017, 2018, 2019, 2020 Luca Saiu 4 Updated in 2021 by Luca Saiu 5 Written by Luca Saiu 6 7 This file is part of Jitter. 8 9 Jitter is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Jitter is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Jitter. If not, see <http://www.gnu.org/licenses/>. */ 21 22 23 #ifndef JITTER_PATCH_IN_H_ 24 #define JITTER_PATCH_IN_H_ 25 26 27 /* Include core headers. 28 * ************************************************************************** */ 29 30 /* Include macro definitions about whether we have a machine file, and about the 31 dispatching model. */ 32 #include <jitter/jitter.h> 33 34 /* Include sectioning macros, if we have section support for this platform. */ 35 #if defined (JITTER_HAVE_KNOWN_BINARY_FORMAT) 36 # include <jitter/jitter-sections.h> 37 #endif // #if defined (JITTER_HAVE_KNOWN_BINARY_FORMAT) 38 39 40 41 42 /* Do nothing if not using patch-ins. 43 * ************************************************************************** */ 44 45 /* First include the machine header which may contain a CPP definition of 46 JITTER_MACHINE_SUPPORTS_PATCH_IN ; this only makes sense if the dispatch is 47 no-threading, which is only possible if assembly is enabled. 48 If the dispatch is different from no-threading patch-ins are always 49 disabled. */ 50 #if defined(JITTER_DISPATCH_NO_THREADING) 51 # include <jitter/jitter-machine-common.h> 52 # include <jitter/machine/jitter-machine.h> 53 # ifdef JITTER_MACHINE_SUPPORTS_PATCH_IN 54 # define JITTER_HAVE_PATCH_IN 1 55 # endif // #ifdef JITTER_MACHINE_SUPPORTS_PATCH_IN 56 #endif //#if defined(JITTER_DISPATCH_NO_THREADING) 57 58 /* The rest of this header expands to nothing if patch-ins are not supported in 59 this configuration. */ 60 #ifdef JITTER_HAVE_PATCH_IN 61 62 63 64 65 /* Include headers. 66 * ************************************************************************** */ 67 68 #include <stdio.h> 69 #include <stdbool.h> 70 71 #include <jitter/jitter.h> 72 #include <jitter/jitter-cpp.h> 73 #include <jitter/jitter-defect.h> 74 #include <jitter/jitter-dynamic-buffer.h> 75 76 77 78 79 /* Introduction. 80 * ************************************************************************** */ 81 82 /* The generated code in .text , to be expanded from VM instructions, will 83 either skip enough bytes for an instruction to be patched-in later, or will 84 generate temporary instructions with some argument to be replaced later; at 85 the same time, the code generates a patch-in descriptor in a separate 86 subsection, referring the preliminary code to patch with enough information 87 to fill-in the missing data after replication. 88 89 GCC may optimize away an entire patch-in, when the code is unreachable or, at 90 least in theory, duplicate it. This is not a problem: if there is no code to 91 patch, no descriptor will refer it; in other words the code in .text 0 and in 92 the subsections are treated as a unit, either both present or both optimized 93 away. For each code sequence to patch there will be one descriptor. 94 95 This relies on the functionality in jitter-sections.h . */ 96 97 98 99 100 /* Fast-branch descriptor data structures: C API. 101 * ************************************************************************** */ 102 103 /* These structures are accessed from C, but their only definition is in assembly 104 code; see the page right below this one. */ 105 106 /* The descriptor for a specific patch-in. Instances of this are defined in 107 assembly, but are meant to be accessed from C as part of a global array. 108 It is convenient that every field be word-sized. Reordering fields requires 109 changes in the assembly code below. */ 110 struct jitter_patch_in_descriptor 111 { 112 /* The specialized instruction opcode for this patch-in. */ 113 jitter_uint specialized_instruction_opcode; 114 115 /* The patch-in offset, in bytes, from the beginning of the specialized 116 instruction code. */ 117 jitter_uint offset; 118 119 /* The patch-in length, in bytes. This information might be redundant if 120 patch_in_case assumes a known length, as it is the case now, but I keep 121 this for future extensibility. */ 122 jitter_uint length; 123 124 /* The patch-in case, indicating the kind of patching to perform. In order to 125 prevent mistakes, zero will not be used as a valid case. */ 126 jitter_uint patch_in_case; 127 128 /* The following fields are case-dependent arguments, not all used for every 129 case. */ 130 131 /* 0-th case-dependent word. Each word is implemented as a union of 132 word-sized elements, to make access more convenient from C code. */ 133 union 134 { 135 /* For a fast goto: fast label index, 0-based. */ 136 jitter_uint residual_index; 137 138 /* Generic 0-th word, as an unsigned datum. */ 139 jitter_uint case_dependent_word_0_uint; 140 141 /* Generic 0-th word, as an signed datum. */ 142 jitter_int case_dependent_word_0_int; 143 } __attribute__ ((packed)); 144 145 /* 1-st case-dependent word, not used yet. */ 146 union 147 { 148 jitter_uint case_dependent_word_1_uint; 149 jitter_int case_dependent_word_1_int; 150 } __attribute__ ((packed)); 151 152 /* 2-nd case-dependent word, not used yet. */ 153 union 154 { 155 jitter_uint case_dependent_word_2_uint; 156 jitter_int case_dependent_word_2_int; 157 } __attribute__ ((packed)); 158 159 /* 3-rd case-dependent word, not used yet. */ 160 union 161 { 162 jitter_uint case_dependent_word_3_uint; 163 jitter_int case_dependent_word_3_int; 164 } __attribute__ ((packed)); 165 } __attribute__ ((packed)); 166 167 168 169 170 /* Prefix-dependent names for globals. 171 * ************************************************************************** */ 172 173 /* The name of the global descriptor vector. */ 174 #define JITTER_PATCH_IN_DESCRIPTORS_NAME(_jitter_vm_the_prefix) \ 175 JITTER_CONCATENATE_TWO(_jitter_vm_the_prefix, \ 176 _patch_in_descriptors) 177 178 /* The name of the global descriptor vector. */ 179 #define JITTER_PATCH_IN_DESCRIPTORS_SIZE_IN_BYTES_NAME(_jitter_vm_the_prefix) \ 180 JITTER_CONCATENATE_TWO(JITTER_PATCH_IN_DESCRIPTORS_NAME( \ 181 _jitter_vm_the_prefix), \ 182 _size_in_bytes) 183 184 /* Expand to extern declaration of the variables defined in assembly, to be used 185 from C. */ 186 #define JITTER_PATCH_IN_DESCRIPTOR_DECLARATIONS_(_jitter_vm_the_prefix) \ 187 extern const struct jitter_patch_in_descriptor \ 188 JITTER_PATCH_IN_DESCRIPTORS_NAME(_jitter_vm_the_prefix) []; \ 189 extern const jitter_uint \ 190 JITTER_PATCH_IN_DESCRIPTORS_SIZE_IN_BYTES_NAME(_jitter_vm_the_prefix); 191 192 193 194 195 /* Patch-in descriptor macros. 196 * ************************************************************************** */ 197 198 /* Each patch-in descriptor contains information about one patch-in 199 placeholder. */ 200 201 /* Expand to a string literal containing the .rodata subsection number 202 containing the patch-in descriptors. */ 203 #define JITTER_ASM_PATCH_IN_SUBSECTION \ 204 "10" 205 206 /* Expand to an inline asm statement containing the patch-in header. Here 207 volatility serves to force this statement to be emitted before the other asm 208 volatile statements within the executor and before the footer, therefore 209 forcing a correct order in the generated assembly file. */ 210 #define JITTER_PATCH_IN_HEADER(_jitter_vm_the_prefix) \ 211 asm (JITTER_ASM_OPEN_DEFINITION \ 212 (JITTER_ASM_PATCH_IN_SUBSECTION, \ 213 JITTER_PATCH_IN_DESCRIPTORS_NAME (_jitter_vm_the_prefix))) 214 215 /* Expand to an inline asm statement containing the patch-in footer. See the 216 comment above.*/ 217 #define JITTER_PATCH_IN_FOOTER(_jitter_vm_the_prefix) \ 218 asm (JITTER_ASM_CLOSE_DEFINITION \ 219 (JITTER_ASM_PATCH_IN_SUBSECTION, \ 220 JITTER_PATCH_IN_DESCRIPTORS_NAME (_jitter_vm_the_prefix))) 221 222 223 224 225 /* Patch-in placeholder macros. 226 * ************************************************************************** */ 227 228 /* Expand to a string literal meant to be used as the the assembly template for 229 a patch-in, referring the named input argument 230 "jitter_vm_instruction_beginning". 231 232 The "l" in the assembly template does *not* indicate a "gotolabel" argument 233 for asm goto: jitter_vm_instruction_beginning is not passed as a gotolabel, 234 but as an ordinary input argument. 235 I used to pass the argument as a gotolabel, but the label was sometimes 236 resolved to a slightly different address compared to what is computed by the 237 prefix && operator under GCC 6 -- which broke patch-ins. Elsewhere in Jitter 238 I use prefix && to delimit the beginning and end of VM instruction code, so 239 it is sensible to always compute these address the same way. 240 241 The "l" modifier serves to omit the immediate-argument prefix "$" on i386 and 242 x86_64, which would be syntactically incorrect in this context, out of an 243 instruction. 244 This "l" is documented in the GCC manual as one of the "x86 Operand 245 Modifiers", but I see it working on any architecture -- doing nothing on 246 architectures different from i386 and x86_64. Should GCC's behavior change 247 in the future it will be trivial to replace "l" with an architecture-specific 248 macro expanding to "l" on i386 and x86_64 and nothing on every other. */ 249 #define JITTER_ASM_PATCH_IN_PLACEHOLDER(size_in_bytes, case, \ 250 arg0, arg1, arg2, arg3) \ 251 JITTER_ASM_COMMENT_UNIQUE("Patch-in " JITTER_STRINGIFY(case)) \ 252 "\n1:\n\t" \ 253 JITTER_ASM_SKIP_BYTES(size_in_bytes) "\n" \ 254 JITTER_ASM_ENTER_SUBSECTION(JITTER_ASM_PATCH_IN_SUBSECTION) \ 255 JITTER_ASM_WORD " " \ 256 JITTER_STRINGIFY(JITTER_SPECIALIZED_INSTRUCTION_OPCODE) "\n\t" \ 257 JITTER_ASM_WORD " (1b - %l[jitter_vm_instruction_beginning])\n\t" \ 258 JITTER_ASM_WORD " " JITTER_STRINGIFY(size_in_bytes) "\n\t" \ 259 JITTER_ASM_WORD " " JITTER_STRINGIFY(case) "\n\t" \ 260 JITTER_ASM_WORD " " JITTER_STRINGIFY(arg0) "\n\t" \ 261 JITTER_ASM_WORD " " JITTER_STRINGIFY(arg1) "\n\t" \ 262 JITTER_ASM_WORD " " JITTER_STRINGIFY(arg2) "\n\t" \ 263 JITTER_ASM_WORD " " JITTER_STRINGIFY(arg3) "\n" \ 264 JITTER_ASM_EXIT_SUBSECTION 265 266 /* Expand to the (named) input constraint jitter_vm_instruction_beginning for an 267 inline asm template generated by JITTER_ASM_PATCH_IN_PLACEHOLDER. 268 269 The constraint is given as "X" rather than the more intuitive "i" because of 270 the SH architecture, where that constraint would fail because of the small 271 immediate size. 272 Should this prove inadequate, it will be easy to make the constraint an 273 architecture-specific macro in the future. Anyway a failure will be very 274 visible, since any problem caused by this will happen early, at compile 275 or assemble time. */ 276 #define JITTER_INPUT_VM_INSTRUCTION_BEGINNING \ 277 [jitter_vm_instruction_beginning] \ 278 "X" (&& JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL) 279 280 /* Likewise for the instruction end. */ 281 #define JITTER_INPUT_VM_INSTRUCTION_END \ 282 [jitter_vm_instruction_end] \ 283 "X" (&& JITTER_SPECIALIZED_INSTRUCTION_END_LABEL) 284 285 /* Expand to a C statement (currently not protected with do..while (false), as 286 this is meant to be only used within other macros) containing the given 287 patch-in for an unconditional VM branch. 288 289 Notice how the (only) input argument is the label for the beginning of the 290 current VM instruction, obtained by the prefix && operator: see the comment 291 before JITTER_ASM_PATCH_IN_PLACEHOLDER . */ 292 #define JITTER_PATCH_IN_PLACEHOLDER_GOTO_(size_in_bytes, case, \ 293 arg0, arg1, arg2, arg3) \ 294 asm goto (JITTER_ASM_DEFECT_DESCRIPTOR \ 295 JITTER_ASM_PATCH_IN_PLACEHOLDER(size_in_bytes, case, \ 296 arg0, arg1, arg2, arg3) \ 297 : /* outputs */ \ 298 : JITTER_PATCH_IN_INPUTS_FOR_EVERY_CASE, \ 299 JITTER_INPUT_VM_INSTRUCTION_BEGINNING /* inputs */ \ 300 : /* clobbers */ \ 301 : jitter_dispatch_label /* gotolabels */) 302 303 /* The inline asm inputs to be used as part of the input constraints for every 304 patch-in. */ 305 #define JITTER_PATCH_IN_INPUTS_FOR_EVERY_CASE \ 306 [_jitter_dummy] "X" (jitter_ip) 307 308 309 310 311 /* Fallback fill-in byte. 312 * ************************************************************************** */ 313 314 /* Unless a definition is not already in machine-specific code. define the byte 315 with which placeholder code is to be filled in. This default is easy to 316 recognize at a glance, but the best choice is machine-specific: ideally the 317 byte should always be invalid at the beginning of an instruction, to make 318 spotting mistakes easier. */ 319 #ifndef JITTER_ASM_PATCH_IN_FILL_BYTE 320 # define JITTER_ASM_PATCH_IN_FILL_BYTE "0xff" 321 #endif // #ifndef JITTER_ASM_PATCH_IN_FILL_BYTE 322 323 324 325 326 /* Patch-in efficient data structures. 327 * ************************************************************************** */ 328 329 /* Compiling code with patch-ins yields an object file containing all the 330 required information, but the subsection hack leaves the data ordered in a 331 very inconvenient and inefficient way. This functionality generates a C 332 array which can be indexed by a specialized instruction opcode, whose 333 elements each point to an array of patch-in descriptor pointers for the 334 specialized instruction. 335 336 The C array can be built just once at initialization time for each VM, at a 337 cost linear in its instruction number. Each patch-in filling, at run time, 338 will then be O(1). */ 339 340 /* The patch-ins for an instruction. */ 341 struct patch_in_table_entry 342 { 343 /* How many descriptors there are. */ 344 size_t descriptor_no; 345 346 /* An array of pointers to descriptrs, of length descriptor_no. */ 347 const struct jitter_patch_in_descriptor **descriptors; 348 }; 349 350 /* Return a freshly allocated C array of struct patch_in_table_entry objects, 351 one element per specialized instruction. */ 352 struct patch_in_table_entry * 353 jitter_make_patch_in_table (const struct jitter_patch_in_descriptor *descs, 354 size_t desc_no, 355 size_t specialized_instruction_no) 356 __attribute__ ((nonnull (1))); 357 358 /* Free resources for a patch-in table as generated by 359 jitter_make_patch_in_table . */ 360 void 361 jitter_destroy_patch_in_table (struct patch_in_table_entry *, 362 size_t specialized_instruction_no) 363 __attribute__ ((nonnull (1))); 364 365 366 367 368 /* Patch-in debugging. 369 * ************************************************************************** */ 370 371 /* Dump the pointed patch-in descriptor in human-readable form to the pointed 372 stream. */ 373 void 374 jitter_dump_patch_in_descriptor (FILE *f, 375 const struct jitter_patch_in_descriptor *p) 376 __attribute__ ((nonnull (1, 2))); 377 378 /* Like jitter_dump_patch_in_descriptor, but prepend the given string to each 379 printed line. */ 380 void 381 jitter_dump_patch_in_descriptor_with_prefix 382 (FILE *f, 383 const char *prefix, 384 const struct jitter_patch_in_descriptor *p) 385 __attribute__ ((nonnull (1, 2, 3))); 386 387 /* Dump the given patch-in descriptor array, having the given size in 388 elements, in human-readable form to the pointed stream. */ 389 void 390 jitter_dump_patch_in_descriptors 391 (FILE *f, 392 const struct jitter_patch_in_descriptor patch_ins [], 393 size_t patch_in_no) 394 __attribute__ ((nonnull (1))); 395 396 /* A convenience macro to call jitter_dump_patch_in_descriptors with the correct 397 parameters. */ 398 #define JITTER_DUMP_PATCH_IN_DESCRIPTORS(_jitter_vm_the_prefix) \ 399 do \ 400 { \ 401 size_t patch_in_no \ 402 = (JITTER_PATCH_IN_DESCRIPTORS_SIZE_IN_BYTES_NAME( \ 403 _jitter_vm_the_prefix) \ 404 / sizeof (struct jitter_patch_in_descriptor)); \ 405 jitter_dump_patch_in_descriptors \ 406 (stderr, \ 407 JITTER_PATCH_IN_DESCRIPTORS_NAME(_jitter_vm_the_prefix), \ 408 patch_in_no); \ 409 } \ 410 while (false) 411 412 #endif // #ifdef JITTER_HAVE_PATCH_IN 413 #endif // #ifndef JITTER_PATCH_IN_H_ 414