| Commit | Line | Data |
|---|---|---|
| eeab7066 RT |
1 | /* |
| 2 | ||
| 3 | This code was written as part of the CMU Common Lisp project at | |
| 4 | Carnegie Mellon University, and has been placed in the public domain. | |
| 5 | ||
| 6 | */ | |
| 5ced0fdf | 7 | |
| 8 | #include <stdio.h> | |
| cb786538 | 9 | #include <stdlib.h> |
| 5ced0fdf | 10 | |
| 11 | #include "lisp.h" | |
| 12 | #include "globals.h" | |
| 13 | #include "validate.h" | |
| 14 | #include "os.h" | |
| 15 | #include "internals.h" | |
| 16 | #include "arch.h" | |
| 17 | #include "lispregs.h" | |
| 18 | #include "signal.h" | |
| 19 | #include "alloc.h" | |
| 20 | #include "interrupt.h" | |
| 21 | #include "interr.h" | |
| 22 | #include "breakpoint.h" | |
| 23 | ||
| 5ced0fdf | 24 | #define BREAKPOINT_INST 0xcc /* INT3 */ |
| 25 | ||
| 9a8c1c2f | 26 | unsigned long fast_random_state = 1; |
| 725ab9ee | 27 | |
| 6438e048 | 28 | #if defined(SOLARIS) |
| 29 | /* | |
| 30 | * Use the /dev/cpu/self/cpuid interface on Solaris. We could use the | |
| 31 | * same method below, but the Sun C compiler miscompiles the inline | |
| 32 | * assembly. | |
| 33 | */ | |
| 34 | ||
| 35 | #include <sys/types.h> | |
| 36 | #include <sys/stat.h> | |
| 37 | #include <fcntl.h> | |
| 38 | #include <unistd.h> | |
| 39 | #include <string.h> | |
| 40 | #include <errno.h> | |
| 41 | ||
| 42 | void cpuid(int level, unsigned int* a, unsigned int* b, | |
| 43 | unsigned int* c, unsigned int* d) | |
| 44 | { | |
| 45 | int device; | |
| 46 | uint32_t regs[4]; | |
| 47 | static const char devname[] = "/dev/cpu/self/cpuid"; | |
| 48 | ||
| 49 | *a = *b = *c = *d = 0; | |
| 50 | if ((device = open(devname, O_RDONLY)) == -1) { | |
| 51 | perror(devname); | |
| 52 | goto exit; | |
| 53 | } | |
| 54 | ||
| 55 | if (pread(device, regs, sizeof(regs), 1) != sizeof(regs)) { | |
| 56 | perror(devname); | |
| 57 | goto exit; | |
| 58 | } | |
| 59 | ||
| 60 | *a = regs[0]; | |
| 61 | *b = regs[1]; | |
| 62 | *c = regs[2]; | |
| 63 | *d = regs[3]; | |
| 64 | ||
| 65 | exit: | |
| 66 | (void) close(device); | |
| 67 | ||
| 68 | return; | |
| 69 | } | |
| 70 | ||
| 71 | #else | |
| cb786538 | 72 | #define __cpuid(level, a, b, c, d) \ |
| 73 | __asm__ ("xchgl\t%%ebx, %1\n\t" \ | |
| 74 | "cpuid\n\t" \ | |
| 75 | "xchgl\t%%ebx, %1\n\t" \ | |
| 76 | : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ | |
| 77 | : "0" (level)) | |
| 78 | ||
| 423bb6de | 79 | void cpuid(int level, unsigned int* a, unsigned int* b, |
| 80 | unsigned int* c, unsigned int* d) | |
| 81 | { | |
| 82 | unsigned int eax, ebx, ecx, edx; | |
| 83 | ||
| 84 | __cpuid(level, eax, ebx, ecx, edx); | |
| 85 | ||
| 86 | *a = eax; | |
| 87 | *b = ebx; | |
| 88 | *c = ecx; | |
| 89 | *d = edx; | |
| 90 | } | |
| 6438e048 | 91 | #endif |
| 423bb6de | 92 | |
| cb786538 | 93 | int |
| 94 | arch_support_sse2(void) | |
| 95 | { | |
| 96 | unsigned int eax, ebx, ecx, edx; | |
| 97 | ||
| 423bb6de | 98 | cpuid(1, &eax, &ebx, &ecx, &edx); |
| cb786538 | 99 | |
| 100 | /* Return non-zero if SSE2 is supported */ | |
| 101 | return edx & 0x4000000; | |
| 102 | } | |
| 103 | ||
| 9a8c1c2f | 104 | char * |
| cb786538 | 105 | arch_init(fpu_mode_t mode) |
| 5ced0fdf | 106 | { |
| cb786538 | 107 | int have_sse2; |
| 108 | ||
| aa9c2237 | 109 | have_sse2 = arch_support_sse2() && os_support_sse2(); |
| cb786538 | 110 | |
| 111 | switch (mode) { | |
| 112 | case AUTO: | |
| 113 | if (have_sse2) { | |
| 114 | return "lisp-sse2.core"; | |
| 115 | } else { | |
| 116 | return "lisp-x87.core"; | |
| 117 | } | |
| 118 | break; | |
| 119 | case X87: | |
| 120 | return "lisp-x87.core"; | |
| 121 | break; | |
| 122 | case SSE2: | |
| 123 | return "lisp-sse2.core"; | |
| 124 | break; | |
| 125 | default: | |
| 126 | abort(); | |
| 127 | } | |
| 5ced0fdf | 128 | } |
| 5ced0fdf | 129 | \f |
| cbdde084 | 130 | |
| 9a8c1c2f | 131 | |
| cbdde084 | 132 | /* |
| 133 | * Assuming we get here via an INT3 xxx instruction, the PC now | |
| 134 | * points to the interrupt code (lisp value) so we just move past | |
| 617e53e5 | 135 | * it. Skip the code, then if the code is an error-trap or |
| cbdde084 | 136 | * Cerror-trap then skip the data bytes that follow. |
| 137 | */ | |
| 138 | ||
| 9a8c1c2f | 139 | void |
| 140 | arch_skip_instruction(os_context_t * context) | |
| 5ced0fdf | 141 | { |
| 9a8c1c2f | 142 | int vlen, code; |
| 143 | ||
| 144 | DPRINTF(0, (stderr, "[arch_skip_inst at %lx>]\n", SC_PC(context))); | |
| 145 | ||
| 146 | /* Get and skip the lisp error code. */ | |
| 147 | code = *(char *) SC_PC(context)++; | |
| 148 | switch (code) { | |
| 149 | case trap_Error: | |
| 150 | case trap_Cerror: | |
| 151 | /* Lisp error arg vector length */ | |
| 152 | vlen = *(char *) SC_PC(context)++; | |
| 153 | /* Skip lisp error arg data bytes */ | |
| 154 | while (vlen-- > 0) | |
| 15454dd9 | 155 | SC_PC(context)++; |
| 9a8c1c2f | 156 | break; |
| 157 | ||
| 158 | case trap_Breakpoint: | |
| 159 | case trap_FunctionEndBreakpoint: | |
| 160 | break; | |
| 161 | ||
| 162 | case trap_PendingInterrupt: | |
| 163 | case trap_Halt: | |
| 164 | /* Only needed to skip the Code. */ | |
| 165 | break; | |
| 166 | ||
| 167 | default: | |
| 168 | fprintf(stderr, "[arch_skip_inst invalid code %d\n]\n", code); | |
| 169 | break; | |
| 5ced0fdf | 170 | } |
| 171 | ||
| 9a8c1c2f | 172 | DPRINTF(0, (stderr, "[arch_skip_inst resuming at %lx>]\n", SC_PC(context))); |
| 5ced0fdf | 173 | } |
| 174 | ||
| 9a8c1c2f | 175 | unsigned char * |
| 176 | arch_internal_error_arguments(os_context_t * context) | |
| 5ced0fdf | 177 | { |
| 9a8c1c2f | 178 | return (unsigned char *) (SC_PC(context) + 1); |
| 5ced0fdf | 179 | } |
| 180 | ||
| 9a8c1c2f | 181 | boolean |
| 182 | arch_pseudo_atomic_atomic(os_context_t * context) | |
| 5ced0fdf | 183 | { |
| 9a8c1c2f | 184 | return SymbolValue(PSEUDO_ATOMIC_ATOMIC); |
| 5ced0fdf | 185 | } |
| 186 | ||
| 9a8c1c2f | 187 | void |
| 188 | arch_set_pseudo_atomic_interrupted(os_context_t * context) | |
| 5ced0fdf | 189 | { |
| 9a8c1c2f | 190 | SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, make_fixnum(1)); |
| 5ced0fdf | 191 | } |
| 192 | \f | |
| cbdde084 | 193 | |
| 9a8c1c2f | 194 | |
| 195 | unsigned long | |
| 196 | arch_install_breakpoint(void *pc) | |
| 5ced0fdf | 197 | { |
| 9a8c1c2f | 198 | unsigned long result = *(unsigned long *) pc; |
| 5ced0fdf | 199 | |
| 9a8c1c2f | 200 | *(char *) pc = BREAKPOINT_INST; /* x86 INT3 */ |
| 201 | *((char *) pc + 1) = trap_Breakpoint; /* Lisp trap code */ | |
| 202 | ||
| 203 | return result; | |
| 5ced0fdf | 204 | } |
| 205 | ||
| 9a8c1c2f | 206 | void |
| 207 | arch_remove_breakpoint(void *pc, unsigned long orig_inst) | |
| 5ced0fdf | 208 | { |
| 9a8c1c2f | 209 | *((char *) pc) = orig_inst & 0xff; |
| 210 | *((char *) pc + 1) = (orig_inst & 0xff00) >> 8; | |
| 5ced0fdf | 211 | } |
| 5ced0fdf | 212 | \f |
| 5ced0fdf | 213 | |
| 9a8c1c2f | 214 | |
| cbdde084 | 215 | /* |
| 216 | * When single stepping single_stepping holds the original instruction | |
| 217 | * pc location. | |
| 218 | */ | |
| 5ced0fdf | 219 | |
| cbdde084 | 220 | unsigned int *single_stepping = NULL; |
| 9a8c1c2f | 221 | |
| 3edae40b | 222 | #ifndef __linux__ |
| 9a8c1c2f | 223 | unsigned int single_step_save1; |
| 224 | unsigned int single_step_save2; | |
| 225 | unsigned int single_step_save3; | |
| 3edae40b | 226 | #endif |
| 227 | ||
| 9a8c1c2f | 228 | void |
| 229 | arch_do_displaced_inst(os_context_t * context, unsigned long orig_inst) | |
| 5ced0fdf | 230 | { |
| 9a8c1c2f | 231 | unsigned int *pc = (unsigned int *) SC_PC(context); |
| cbdde084 | 232 | |
| 9a8c1c2f | 233 | /* |
| 234 | * Put the original instruction back. | |
| 235 | */ | |
| 3edae40b | 236 | |
| 9a8c1c2f | 237 | *((char *) pc) = orig_inst & 0xff; |
| 238 | *((char *) pc + 1) = (orig_inst & 0xff00) >> 8; | |
| 3edae40b | 239 | |
| 5c6f325d | 240 | #ifdef SC_EFLAGS |
| 7d7c3c3e | 241 | /* Enable single-stepping */ |
| 5c6f325d | 242 | SC_EFLAGS(context) |= 0x100; |
| 3edae40b | 243 | #else |
| cbdde084 | 244 | |
| 9a8c1c2f | 245 | /* |
| 246 | * Install helper instructions for the single step: | |
| 7d7c3c3e | 247 | * nop; nop; nop; pushf; or [esp],0x100; popf. |
| 248 | * | |
| 249 | * The or instruction enables the trap flag which enables | |
| 250 | * single-stepping. So when the popf instruction is run, we start | |
| 251 | * single-stepping and stop on the next instruction. | |
| 9a8c1c2f | 252 | */ |
| 253 | ||
| ac087c01 | 254 | DPRINTF(0, (stderr, "Installing helper instructions\n")); |
| 78eb5a7b | 255 | |
| 9a8c1c2f | 256 | single_step_save1 = *(pc - 3); |
| 257 | single_step_save2 = *(pc - 2); | |
| 258 | single_step_save3 = *(pc - 1); | |
| 259 | *(pc - 3) = 0x9c909090; | |
| 260 | *(pc - 2) = 0x00240c81; | |
| 261 | *(pc - 1) = 0x9d000001; | |
| 3edae40b | 262 | #endif |
| 263 | ||
| 9a8c1c2f | 264 | single_stepping = (unsigned int *) pc; |
| 3edae40b | 265 | |
| 78eb5a7b | 266 | #ifndef SC_EFLAGS |
| 7d7c3c3e | 267 | /* |
| 268 | * pc - 9 points to the pushf instruction that we installed for | |
| 269 | * the helper. | |
| 270 | */ | |
| 271 | ||
| ac087c01 | 272 | DPRINTF(0, (stderr, " Setting pc to pushf instruction at %p\n", (void*) ((char*) pc - 9))); |
| caa5a031 | 273 | SC_PC(context) = (int)((char *) pc - 9); |
| 3edae40b | 274 | #endif |
| 5ced0fdf | 275 | } |
| 276 | \f | |
| 5ced0fdf | 277 | |
| 9a8c1c2f | 278 | void |
| 279 | sigtrap_handler(HANDLER_ARGS) | |
| 5ced0fdf | 280 | { |
| 9a8c1c2f | 281 | unsigned int trap; |
| aa96ed2c | 282 | os_context_t* os_context = (os_context_t *) context; |
| cbdde084 | 283 | #if 0 |
| 78eb5a7b | 284 | fprintf(stderr, "x86sigtrap: %8x %x\n", |
| aa96ed2c RT |
285 | SC_PC(os_os_context), *(unsigned char *) (SC_PC(os_context) - 1)); |
| 286 | fprintf(stderr, "sigtrap(%d %d %x)\n", signal, CODE(code), os_context); | |
| cbdde084 | 287 | #endif |
| 288 | ||
| 9a8c1c2f | 289 | if (single_stepping && (signal == SIGTRAP)) { |
| cbdde084 | 290 | #if 0 |
| 7d7c3c3e | 291 | fprintf(stderr, "* Single step trap %p\n", single_stepping); |
| cbdde084 | 292 | #endif |
| 3edae40b | 293 | |
| 5c6f325d | 294 | #ifdef SC_EFLAGS |
| 7d7c3c3e | 295 | /* Disable single-stepping */ |
| aa96ed2c | 296 | SC_EFLAGS(os_context) ^= 0x100; |
| 7d7c3c3e | 297 | #else |
| 9a8c1c2f | 298 | /* Un-install single step helper instructions. */ |
| 299 | *(single_stepping - 3) = single_step_save1; | |
| 300 | *(single_stepping - 2) = single_step_save2; | |
| 301 | *(single_stepping - 1) = single_step_save3; | |
| ac087c01 | 302 | DPRINTF(0, (stderr, "Uninstalling helper instructions\n")); |
| a3a119cd | 303 | #endif |
| cbdde084 | 304 | |
| 9a8c1c2f | 305 | /* |
| 306 | * Re-install the breakpoint if possible. | |
| 307 | */ | |
| aa96ed2c | 308 | if ((int) SC_PC(os_context) == (int) single_stepping + 1) |
| 9a8c1c2f | 309 | fprintf(stderr, "* Breakpoint not re-install\n"); |
| 310 | else { | |
| 311 | char *ptr = (char *) single_stepping; | |
| 312 | ||
| 313 | ptr[0] = BREAKPOINT_INST; /* x86 INT3 */ | |
| 314 | ptr[1] = trap_Breakpoint; | |
| 3edae40b | 315 | } |
| 316 | ||
| 9a8c1c2f | 317 | single_stepping = NULL; |
| 318 | return; | |
| 3edae40b | 319 | } |
| a3a119cd | 320 | |
| 9a8c1c2f | 321 | /* This is just for info in case monitor wants to print an approx */ |
| aa96ed2c | 322 | current_control_stack_pointer = (unsigned long *) SC_SP(os_context); |
| 3edae40b | 323 | |
| aa96ed2c | 324 | RESTORE_FPU(os_context); |
| 44eba57f | 325 | |
| 9a8c1c2f | 326 | /* |
| 327 | * On entry %eip points just after the INT3 byte and aims at the | |
| 328 | * 'kind' value (eg trap_Cerror). For error-trap and Cerror-trap a | |
| 329 | * number of bytes will follow, the first is the length of the byte | |
| 330 | * arguments to follow. | |
| 331 | */ | |
| 332 | ||
| aa96ed2c | 333 | trap = *(unsigned char *) SC_PC(os_context); |
| 9a8c1c2f | 334 | |
| 335 | switch (trap) { | |
| 336 | case trap_PendingInterrupt: | |
| 337 | DPRINTF(0, (stderr, "<trap Pending Interrupt.>\n")); | |
| aa96ed2c RT |
338 | arch_skip_instruction(os_context); |
| 339 | interrupt_handle_pending(os_context); | |
| 9a8c1c2f | 340 | break; |
| 341 | ||
| 342 | case trap_Halt: | |
| 343 | { | |
| c07cc020 RT |
344 | FPU_STATE(fpu_state); |
| 345 | save_fpu_state(fpu_state); | |
| 9a8c1c2f | 346 | |
| aa96ed2c | 347 | fake_foreign_function_call(os_context); |
| 9a8c1c2f | 348 | lose("%%primitive halt called; the party is over.\n"); |
| aa96ed2c | 349 | undo_fake_foreign_function_call(os_context); |
| c07cc020 RT |
350 | |
| 351 | restore_fpu_state(fpu_state); | |
| aa96ed2c | 352 | arch_skip_instruction(os_context); |
| 9a8c1c2f | 353 | break; |
| 354 | } | |
| 355 | ||
| 356 | case trap_Error: | |
| 357 | case trap_Cerror: | |
| 342beebb | 358 | DPRINTF(0, (stderr, "<trap Error %x>\n", CODE(code))); |
| aa96ed2c | 359 | interrupt_internal_error(signal, code, os_context, CODE(code) == trap_Cerror); |
| 9a8c1c2f | 360 | break; |
| cbdde084 | 361 | |
| 9a8c1c2f | 362 | case trap_Breakpoint: |
| cbdde084 | 363 | #if 0 |
| 9a8c1c2f | 364 | fprintf(stderr, "*C break\n"); |
| cbdde084 | 365 | #endif |
| aa96ed2c | 366 | SC_PC(os_context) -= 1; |
| 5d2cd5df | 367 | |
| aa96ed2c | 368 | handle_breakpoint(signal, CODE(code), os_context); |
| cbdde084 | 369 | #if 0 |
| 9a8c1c2f | 370 | fprintf(stderr, "*C break return\n"); |
| cbdde084 | 371 | #endif |
| 9a8c1c2f | 372 | break; |
| 373 | ||
| 374 | case trap_FunctionEndBreakpoint: | |
| aa96ed2c RT |
375 | SC_PC(os_context) -= 1; |
| 376 | SC_PC(os_context) = | |
| 377 | (int) handle_function_end_breakpoint(signal, CODE(code), os_context); | |
| 9a8c1c2f | 378 | break; |
| 379 | ||
| 10d10ac0 | 380 | #ifdef trap_DynamicSpaceOverflowWarning |
| 9a8c1c2f | 381 | case trap_DynamicSpaceOverflowWarning: |
| 382 | interrupt_handle_space_overflow(SymbolFunction | |
| 383 | (DYNAMIC_SPACE_OVERFLOW_WARNING_HIT), | |
| aa96ed2c | 384 | os_context); |
| 9a8c1c2f | 385 | break; |
| 10d10ac0 | 386 | #endif |
| 387 | #ifdef trap_DynamicSpaceOverflowError | |
| 9a8c1c2f | 388 | case trap_DynamicSpaceOverflowError: |
| 389 | interrupt_handle_space_overflow(SymbolFunction | |
| 390 | (DYNAMIC_SPACE_OVERFLOW_ERROR_HIT), | |
| aa96ed2c | 391 | os_context); |
| 9a8c1c2f | 392 | break; |
| 10d10ac0 | 393 | #endif |
| 9a8c1c2f | 394 | default: |
| 395 | DPRINTF(0, | |
| f3e5780e | 396 | (stderr, "[C--trap default %d %d %p]\n", signal, CODE(code), |
| aa96ed2c RT |
397 | os_context)); |
| 398 | interrupt_handle_now(signal, code, os_context); | |
| 9a8c1c2f | 399 | break; |
| 5ced0fdf | 400 | } |
| 401 | } | |
| 402 | ||
| 9a8c1c2f | 403 | void |
| b8d0dfaf | 404 | arch_install_interrupt_handlers(void) |
| 5ced0fdf | 405 | { |
| cbdde084 | 406 | interrupt_install_low_level_handler(SIGILL, sigtrap_handler); |
| 407 | interrupt_install_low_level_handler(SIGTRAP, sigtrap_handler); | |
| 5ced0fdf | 408 | } |
| 409 | \f | |
| 410 | ||
| 9a8c1c2f | 411 | extern lispobj call_into_lisp(lispobj fun, lispobj * args, int nargs); |
| 5ced0fdf | 412 | |
| 413 | /* These next four functions are an interface to the | |
| 414 | * Lisp call-in facility. Since this is C we can know | |
| 415 | * nothing about the calling environment. The control | |
| 416 | * stack might be the C stack if called from the monitor | |
| 417 | * or the Lisp stack if called as a result of an interrupt | |
| 418 | * or maybe even a separate stack. The args are most likely | |
| 419 | * on that stack but could be in registers depending on | |
| 420 | * what the compiler likes. So I try to package up the | |
| 421 | * args into a portable vector and let the assembly language | |
| 422 | * call-in function figure it out. | |
| 423 | */ | |
| cbdde084 | 424 | |
| 9a8c1c2f | 425 | lispobj |
| 426 | funcall0(lispobj function) | |
| 5ced0fdf | 427 | { |
| 428 | lispobj *args = NULL; | |
| 429 | ||
| 430 | return call_into_lisp(function, args, 0); | |
| 431 | } | |
| 432 | ||
| 9a8c1c2f | 433 | lispobj |
| 434 | funcall1(lispobj function, lispobj arg0) | |
| 5ced0fdf | 435 | { |
| 436 | lispobj args[1]; | |
| 9a8c1c2f | 437 | |
| 5ced0fdf | 438 | args[0] = arg0; |
| 439 | return call_into_lisp(function, args, 1); | |
| 440 | } | |
| 441 | ||
| 9a8c1c2f | 442 | lispobj |
| 443 | funcall2(lispobj function, lispobj arg0, lispobj arg1) | |
| 5ced0fdf | 444 | { |
| 445 | lispobj args[2]; | |
| 9a8c1c2f | 446 | |
| 5ced0fdf | 447 | args[0] = arg0; |
| 448 | args[1] = arg1; | |
| 449 | return call_into_lisp(function, args, 2); | |
| 450 | } | |
| 451 | ||
| 9a8c1c2f | 452 | lispobj |
| 453 | funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2) | |
| 5ced0fdf | 454 | { |
| 455 | lispobj args[3]; | |
| 9a8c1c2f | 456 | |
| 5ced0fdf | 457 | args[0] = arg0; |
| 458 | args[1] = arg1; | |
| 459 | args[2] = arg2; | |
| 460 | return call_into_lisp(function, args, 3); | |
| 461 | } | |
| bf84be07 | 462 | |
| cf055d22 | 463 | #ifdef LINKAGE_TABLE |
| 464 | ||
| f055faed | 465 | #ifndef LinkageEntrySize |
| 466 | #define LinkageEntrySize 8 | |
| 467 | #endif | |
| bf84be07 | 468 | |
| 9a8c1c2f | 469 | void |
| 470 | arch_make_linkage_entry(long linkage_entry, void *target_addr, long type) | |
| bf84be07 | 471 | { |
| 9a8c1c2f | 472 | char *reloc_addr = (char *) (FOREIGN_LINKAGE_SPACE_START |
| bf84be07 | 473 | |
| 9a8c1c2f | 474 | + linkage_entry * LinkageEntrySize); |
| 475 | ||
| 476 | if (type == 1) { /* code reference */ | |
| 477 | /* Make JMP to function entry. */ | |
| bf84be07 | 478 | /* JMP offset is calculated from next instruction. */ |
| 9a8c1c2f | 479 | long offset = (char *) target_addr - (reloc_addr + 5); |
| bf84be07 | 480 | int i; |
| 9a8c1c2f | 481 | |
| 482 | *reloc_addr++ = 0xe9; /* opcode for JMP rel32 */ | |
| bf84be07 | 483 | for (i = 0; i < 4; i++) { |
| 484 | *reloc_addr++ = offset & 0xff; | |
| 485 | offset >>= 8; | |
| 486 | } | |
| 487 | /* write a nop for good measure. */ | |
| 488 | *reloc_addr = 0x90; | |
| 489 | } else if (type == 2) { | |
| 9a8c1c2f | 490 | *(unsigned long *) reloc_addr = (unsigned long) target_addr; |
| bf84be07 | 491 | } |
| 492 | } | |
| 493 | ||
| 494 | /* Make a call to the first function in the linkage table, which is | |
| 495 | resolve_linkage_tramp. */ | |
| 9a8c1c2f | 496 | void |
| 497 | arch_make_lazy_linkage(long linkage_entry) | |
| bf84be07 | 498 | { |
| 9a8c1c2f | 499 | char *reloc_addr = (char *) (FOREIGN_LINKAGE_SPACE_START |
| 500 | ||
| 501 | + linkage_entry * LinkageEntrySize); | |
| 502 | long offset = (char *) (FOREIGN_LINKAGE_SPACE_START) - (reloc_addr + 5); | |
| bf84be07 | 503 | int i; |
| 504 | ||
| 9a8c1c2f | 505 | *reloc_addr++ = 0xe8; /* opcode for CALL rel32 */ |
| bf84be07 | 506 | for (i = 0; i < 4; i++) { |
| 507 | *reloc_addr++ = offset & 0xff; | |
| 508 | offset >>= 8; | |
| 509 | } | |
| 510 | /* write a nop for good measure. */ | |
| 511 | *reloc_addr = 0x90; | |
| 512 | } | |
| 513 | ||
| 514 | /* Get linkage entry. The initial instruction in the linkage | |
| 515 | entry is a CALL; the return address we're passed points to the next | |
| 516 | instruction. */ | |
| 517 | ||
| 9a8c1c2f | 518 | long |
| 519 | arch_linkage_entry(unsigned long retaddr) | |
| bf84be07 | 520 | { |
| f055faed | 521 | return ((retaddr - 5) - FOREIGN_LINKAGE_SPACE_START) / LinkageEntrySize; |
| bf84be07 | 522 | } |
| 523 | #endif /* LINKAGE_TABLE */ | |
| a459a234 | 524 | |
| 525 | int ieee754_rem_pio2(double x, double *y0, double *y1) | |
| 526 | { | |
| 527 | extern int __ieee754_rem_pio2(double x, double *y); | |
| 528 | ||
| 529 | double y[2]; | |
| 530 | int n; | |
| 531 | ||
| 532 | n = __ieee754_rem_pio2(x, y); | |
| 533 | *y0 = y[0]; | |
| 534 | *y1 = y[1]; | |
| 535 | ||
| 536 | return n; | |
| 537 | } | |
| 538 | ||
| 539 |