You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

657 lines
21 KiB

/*
* Copyright 2002-2019 Intel Corporation.
*
* This software is provided to you as Sample Source Code as defined in the accompanying
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
* section 1.L.
*
* This software and the related documents are provided as is, with no express or implied
* warranties, other than those that are expressly stated in the License.
*/
#define _GNU_SOURCE
#ifdef TARGET_MAC
# include <sys/ucontext.h>
# include <mach/mach.h>
# include <stdbool.h>
#else
# include <ucontext.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/utsname.h>
#include "raise-exception-addrs.h"
#include "faultcheck-target.h"
#define PAGESIZE 4096
/* When an executable is position independent, it may load into any location.
* This causes a problem when diffing the outputs of two runs of this program.
* We can solve this by only comparing the page offsets, which should remain
* constant between runs. If, for debugging purposes, full addresses are
* needed, define NORMALIZE_ADDRESSES as 0.
*/
#define NORMALIZE_ADDRESSES 1
uintptr_t normalize_addr(uintptr_t addr) {
if (NORMALIZE_ADDRESSES) {
addr = addr & (PAGESIZE - 1);
}
return addr;
}
extern void DoUnmappedWrite(void *);
extern void DoUnmappedRead(void *);
extern void DoInaccessibleRead(void *);
extern void DoInaccessibleWrite(void *);
extern void DoUD2();
extern void DoPrivilegedInstruction();
extern void DoIntegerDivideByZero();
extern void DoIntegerOverflowTrap();
extern void DoX87DivideByZero();
extern void DoX87Overflow();
extern void DoX87Underflow();
extern void DoX87Precision();
extern void DoX87InvalidOperation();
extern void DoX87DenormalizedOperand();
extern void DoX87StackUnderflow();
extern void DoX87StackOverflow();
extern void DoX87MultipleExceptions();
extern void DoSIMDDivideByZero();
extern void DoSIMDOverflow();
extern void DoSIMDUnderflow();
extern void DoSIMDPrecision();
extern void DoSIMDInvalidOperation();
extern void DoSIMDDenormalizedOperand();
extern void DoSIMDMultipleExceptions();
extern void DoBreakpointTrap();
extern void DoSingleStepTrap();
extern void DoBadRegister();
extern void ClearAC();
extern void DoIllegalSetOfSegReg1();
extern void DoIllegalSetOfSegReg2();
extern void DoIllegalSetOfSegReg3();
extern void DoIllegalGetOfSegReg1();
extern void DoIllegalGetOfSegReg2();
extern char PinLab_UnmappedRead;
extern char PinLab_UnmappedWrite;
extern char PinLab_InaccessibleRead;
extern char PinLab_InaccessibleWrite;
extern char PinLab_MisalignedRead;
extern char PinLab_MisalignedWrite;
extern char PinLab_IllegalInstruction;
extern char PinLab_PrivilegedInstruction;
extern char PinLab_IntegerDivideByZero;
extern char PinLab_IntegerOverflowTrap;
extern char PinLab_X87DivideByZero;
extern char PinLab_X87Overflow;
extern char PinLab_X87Underflow;
extern char PinLab_X87Precision;
extern char PinLab_X87InvalidOperation;
extern char PinLab_X87DenormalizedOperand;
extern char PinLab_X87StackUnderflow;
extern char PinLab_X87StackOverflow;
extern char PinLab_X87MultipleExceptions;
extern char PinLab_SIMDDivideByZero;
extern char PinLab_SIMDOverflow;
extern char PinLab_SIMDUnderflow;
extern char PinLab_SIMDPrecision;
extern char PinLab_SIMDInvalidOperation;
extern char PinLab_SIMDDenormalizedOperand;
extern char PinLab_SIMDMultipleExceptions;
extern char PinLab_BreakpointTrap;
#if defined(TARGET_IA32) && !defined(TARGET_MAC)
extern void DoBoundTrap();
extern char PinLab_BoundTrap;
#endif
#define BYTES_PER_TRAP_FUNC 3 /* number bytes in each "IntTrap" function */
#define NUM_TRAP_FUNCS 256 /* number of "IntTrap" functions */
static char NoPermBuffer[2*PAGESIZE];
static void *PageNoPerm = 0;
static char MisalignedBuffer[16];
static void *MisalignedAddress = 0;
static void *UnmappedAddress = (void *)8;
#if !defined(TARGET_MAC)
static unsigned char IntTrapBuffer[3*PAGESIZE];
#endif
static unsigned char *IntTrapCode;
static int IsBadKernel;
static int PrintSiAddr;
static int PrintMxcsr;
static int PrintX87Status;
/*
* Do one-time initializations for the tests. Returns 1 on success, 0 on failure.
*/
int Initialize()
{
RAISE_EXCEPTION_ADDRS pinAddrs;
struct utsname uinfo;
unsigned long addr;
int trapNo;
int i;
/*
* Create a page without read or write permission.
*/
if (getpagesize() != PAGESIZE)
{
fprintf(stderr, "Wrong page size\n");
return 0;
}
addr = (unsigned long)&NoPermBuffer[0];
addr = (addr + PAGESIZE) & ~(PAGESIZE-1);
PageNoPerm = (void *)addr;
if (mprotect(PageNoPerm, PAGESIZE, 0) != 0)
{
fprintf(stderr, "mprotect failed\n");
return 0;
}
/*
* Get a misaligned pointer to a 8-byte buffer.
*/
addr = (unsigned long)&MisalignedBuffer[0];
MisalignedAddress = (void *)(((addr + 8) & ~7) + 1);
/*
* Create code for all possible 'INT x' instructions. We construct the code
* so that it falls at the end of a page and the next page is not accessible.
* This helps test SMC. See Mantis #1795.
*/
#if defined(TARGET_MAC)
// Starting from macOS 10.15, statically allocated memory doesn't have execute permission and cannot be modified to have
// execute permission. Therefore dynamically allocating this memory (which allows adding execute permission).
addr = (unsigned long)malloc (3*PAGESIZE);
#else
addr = (unsigned long)&IntTrapBuffer[0];
#endif
addr = (addr + PAGESIZE) & ~(PAGESIZE-1);
if (mprotect((void *)addr, PAGESIZE, (PROT_READ|PROT_WRITE|PROT_EXEC)) != 0)
{
fprintf(stderr, "mprotect failed\n");
return 0;
}
if (mprotect((void *)(addr+PAGESIZE), PAGESIZE, 0) != 0)
{
fprintf(stderr, "mprotect failed\n");
return 0;
}
IntTrapCode = (void *)(addr + PAGESIZE - BYTES_PER_TRAP_FUNC * NUM_TRAP_FUNCS);
for (i = 0, trapNo = 0; trapNo < NUM_TRAP_FUNCS; trapNo++)
{
IntTrapCode[i++] = 0xcd; /* int <trapNo> */
IntTrapCode[i++] = trapNo;
IntTrapCode[i++] = 0xc3; /* ret */
}
assert(i == BYTES_PER_TRAP_FUNC * NUM_TRAP_FUNCS);
/*
* Tell the Pin tool about the labels for some of the instructions that raise
* exceptions. The tool may instrument these instructions.
*/
memset(&pinAddrs, 0, sizeof(pinAddrs));
pinAddrs._unmappedRead = &PinLab_UnmappedRead;
pinAddrs._unmappedReadAddr = UnmappedAddress;
pinAddrs._unmappedWrite = &PinLab_UnmappedWrite;
pinAddrs._unmappedWriteAddr = UnmappedAddress;
pinAddrs._inaccessibleRead = &PinLab_InaccessibleRead;
pinAddrs._inaccessibleReadAddr = PageNoPerm;
pinAddrs._inaccessibleWrite = &PinLab_InaccessibleWrite;
pinAddrs._inaccessibleWriteAddr = PageNoPerm;
pinAddrs._misalignedRead = &PinLab_MisalignedRead;
pinAddrs._misalignedWrite = &PinLab_MisalignedWrite;
pinAddrs._illegalInstruction = &PinLab_IllegalInstruction;
pinAddrs._privilegedInstruction = &PinLab_PrivilegedInstruction;
pinAddrs._integerDivideByZero = &PinLab_IntegerDivideByZero;
pinAddrs._integerOverflowTrap = &PinLab_IntegerOverflowTrap;
#if defined(TARGET_IA32) && !defined(TARGET_MAC)
pinAddrs._boundTrap = &PinLab_BoundTrap;
#endif
pinAddrs._x87DivideByZero = &PinLab_X87DivideByZero;
pinAddrs._x87Overflow = &PinLab_X87Overflow;
pinAddrs._x87Underflow = &PinLab_X87Underflow;
pinAddrs._x87Precision = &PinLab_X87Precision;
pinAddrs._x87InvalidOperation = &PinLab_X87InvalidOperation;
pinAddrs._x87DenormalizedOperand = &PinLab_X87DenormalizedOperand;
pinAddrs._x87StackUnderflow = &PinLab_X87StackUnderflow;
pinAddrs._x87StackOverflow = &PinLab_X87StackOverflow;
pinAddrs._x87MultipleExceptions = &PinLab_X87MultipleExceptions;
pinAddrs._simdDivideByZero = &PinLab_SIMDDivideByZero;
pinAddrs._simdOverflow = &PinLab_SIMDOverflow;
pinAddrs._simdUnderflow = &PinLab_SIMDUnderflow;
pinAddrs._simdPrecision = &PinLab_SIMDPrecision;
pinAddrs._simdInvalidOperation = &PinLab_SIMDInvalidOperation;
pinAddrs._simdDenormalizedOperand = &PinLab_SIMDDenormalizedOperand;
pinAddrs._simdMultipleExceptions = &PinLab_SIMDMultipleExceptions;
pinAddrs._breakpointTrap = &PinLab_BreakpointTrap;
SetLabelsForPinTool(&pinAddrs);
/*
* Some RHEL3 kernels are known to be broken in a way that causes this
* test to fail. Kernels "2.4.21-17" (Taroon Update 3) are known broken,
* while kernels "2.4.21-37" (Taroon Update 6) are known to be OK. If we
* discover other broken kernel versions, the test below should be updated.
*
* Broken kernels only appear to be broken when running an IA32 application
* on an Intel64 kernel. In the broken case, the kernel appears to leave
* the "si_code" field uninitialized in the siginfo_t structure. This confuses
* Pin (resulting in a Pin crash) for some of the tests below. Other tests
* fail simply because Pin emulates the correct si_code value. However the test
* fails because, we compare the Pin emulated si_code value against the native
* si_code value.
*/
IsBadKernel = 0;
#if defined(TARGET_IA32)
if (uname(&uinfo) == 0)
{
if ((strncmp(uinfo.machine, "x86_64", sizeof("x86_64")-1) == 0) &&
(strncmp(uinfo.release, "2.4.21-17", sizeof("2.4.21-17")-1) == 0))
{
IsBadKernel = 1;
}
}
#endif
return 1;
}
TSTATUS DoTest(unsigned int tnum)
{
unsigned int trapNo;
void (*fn)();
PrintSiAddr = 0;
PrintMxcsr = 0;
PrintX87Status = 0;
switch (tnum)
{
case 0:
printf(" Read from unmapped address (EXCEPTCODE_ACCESS_INVALID_ADDRESS)\n");
PrintSiAddr = 1;
DoUnmappedRead(UnmappedAddress);
return TSTATUS_NOFAULT;
case 1:
printf(" Write to unmapped address (EXCEPTCODE_ACCESS_INVALID_ADDRESS)\n");
PrintSiAddr = 1;
DoUnmappedWrite(UnmappedAddress);
return TSTATUS_NOFAULT;
case 2:
printf(" Jump to unmapped address (EXCEPTCODE_ACCESS_INVALID_ADDRESS)\n");
#if !defined(TARGET_BSD)
if (!IsBadKernel)
{
PrintSiAddr = 1;
fn = UnmappedAddress;
fn();
return TSTATUS_NOFAULT;
}
else
{
return TSTATUS_SKIP;
}
#else
/* BSD does not support jumping to invalid code yet. See Mantis #1940 */
return TSTATUS_SKIP;
#endif
case 3:
printf(" Read from inaccessible address (EXCEPTCODE_ACCESS_DENIED)\n");
PrintSiAddr = 1;
DoInaccessibleRead(PageNoPerm);
return TSTATUS_NOFAULT;
case 4:
printf(" Write to inaccessible address (EXCEPTCODE_ACCESS_DENIED)\n");
PrintSiAddr = 1;
DoInaccessibleWrite(PageNoPerm);
return TSTATUS_NOFAULT;
case 5:
printf(" Jump to inaccessible address (EXCEPTCODE_ACCESS_DENIED)\n");
#if !defined(TARGET_BSD)
if (!IsBadKernel)
{
PrintSiAddr = 1;
fn = PageNoPerm;
fn();
return TSTATUS_NOFAULT;
}
else
{
return TSTATUS_SKIP;
}
#else
/* BSD does not support jumping to invalid code yet. See Mantis #1940 */
return TSTATUS_SKIP;
#endif
case 6:
printf(" Read from misaligned address (EXCEPTCODE_ACCESS_MISALIGNED)\n");
#if !defined(TARGET_BSD) && !defined(TARGET_MAC)
DoMisalignedRead(MisalignedAddress);
return TSTATUS_NOFAULT;
#else
/* This causes problems on BSD. See Mantis #1940 */
return TSTATUS_SKIP;
#endif
case 7:
printf(" Write to misaligned address (EXCEPTCODE_ACCESS_MISALIGNED)\n");
#if !defined(TARGET_BSD) && !defined(TARGET_MAC)
DoMisalignedWrite(MisalignedAddress);
return TSTATUS_NOFAULT;
#else
/* This causes problems on BSD. See Mantis #1940 */
return TSTATUS_SKIP;
#endif
case 8:
printf(" Execute illegal instruction (EXCEPTCODE_ILLEGAL_INS)\n");
PrintSiAddr = 1;
DoUD2();
return TSTATUS_NOFAULT;
case 9:
printf(" Execute privileged instruction (EXCEPTCODE_PRIVILEGED_INS)\n");
DoPrivilegedInstruction();
return TSTATUS_NOFAULT;
case 10:
printf(" Integer divide by zero (EXCEPTCODE_INT_DIVIDE_BY_ZERO)\n");
PrintSiAddr = 1;
DoIntegerDivideByZero();
return TSTATUS_NOFAULT;
case 11:
printf(" Integer overflow trap (EXCEPTCODE_INT_OVERFLOW_TRAP)\n");
DoIntegerOverflowTrap();
return TSTATUS_NOFAULT;
case 12:
printf(" Array index bound trap (EXCEPTCODE_INT_BOUNDS_EXCEEDED)\n");
#if defined(TARGET_IA32) && !defined(TARGET_MAC)
/*
* The BOUND instruction only exists on IA32.
* GCC/GAS on macOS* does not support assemblying the bound instruction
*/
DoBoundTrap();
return TSTATUS_NOFAULT;
#else
return TSTATUS_SKIP;
#endif
case 13:
printf(" X87 divide by zero (EXCEPTCODE_X87_DIVIDE_BY_ZERO)\n");
PrintSiAddr = 1;
PrintX87Status = 1;
DoX87DivideByZero();
return TSTATUS_NOFAULT;
case 14:
printf(" X87 overflow (EXCEPTCODE_X87_OVERFLOW)\n");
PrintSiAddr = 1;
PrintX87Status = 1;
DoX87Overflow();
return TSTATUS_NOFAULT;
case 15:
printf(" X87 underflow (EXCEPTCODE_X87_UNDERFLOW)\n");
PrintSiAddr = 1;
PrintX87Status = 1;
DoX87Underflow();
return TSTATUS_NOFAULT;
case 16:
printf(" X87 precision (EXCEPTCODE_X87_INEXACT_RESULT)\n");
PrintSiAddr = 1;
PrintX87Status = 1;
DoX87Precision();
return TSTATUS_NOFAULT;
case 17:
printf(" X87 invalid operation (EXCEPTCODE_X87_INVALID_OPERATION)\n");
PrintSiAddr = 1;
PrintX87Status = 1;
DoX87InvalidOperation();
return 1;
case 18:
printf(" X87 denormalized operand (EXCEPTCODE_X87_DENORMAL_OPERAND)\n");
PrintSiAddr = 1;
PrintX87Status = 1;
DoX87DenormalizedOperand();
return TSTATUS_NOFAULT;
case 19:
printf(" X87 stack underflow (EXCEPTCODE_X87_STACK_ERROR)\n");
PrintSiAddr = 1;
PrintX87Status = 1;
DoX87StackUnderflow();
return TSTATUS_NOFAULT;
case 20:
printf(" X87 stack overflow (EXCEPTCODE_X87_STACK_ERROR)\n");
PrintSiAddr = 1;
PrintX87Status = 1;
DoX87StackOverflow();
return 1;
case 21:
printf(" X87 multiple exceptions\n");
PrintSiAddr = 1;
PrintX87Status = 1;
DoX87MultipleExceptions();
return 1;
case 22:
#if !defined(TARGET_MAC)
printf(" SIMD divide by zero (EXCEPTCODE_SIMD_DIVIDE_BY_ZERO)\n");
PrintSiAddr = 1;
PrintMxcsr = 1;
DoSIMDDivideByZero();
return TSTATUS_NOFAULT;
#else
/* This causes problems on macOS* */
return TSTATUS_SKIP;
#endif
case 23:
printf(" SIMD overflow (EXCEPTCODE_SIMD_OVERFLOW)\n");
PrintSiAddr = 1;
PrintMxcsr = 1;
DoSIMDOverflow();
return TSTATUS_NOFAULT;
case 24:
printf(" SIMD underflow (EXCEPTCODE_SIMD_UNDERFLOW)\n");
PrintSiAddr = 1;
PrintMxcsr = 1;
DoSIMDUnderflow();
return TSTATUS_NOFAULT;
case 25:
printf(" SIMD precision (EXCEPTCODE_SIMD_INEXACT_RESULT)\n");
PrintSiAddr = 1;
PrintMxcsr = 1;
DoSIMDPrecision();
return TSTATUS_NOFAULT;
case 26:
#if !defined(TARGET_MAC)
printf(" SIMD invalid operation (EXCEPTCODE_SIMD_INVALID_OPERATION)\n");
PrintSiAddr = 1;
PrintMxcsr = 1;
DoSIMDInvalidOperation();
return TSTATUS_NOFAULT;
#else
/* This causes problems on macOS* */
return TSTATUS_SKIP;
#endif
case 27:
#if !defined(TARGET_MAC)
printf(" SIMD denormalized operand (EXCEPTCODE_SIMD_DENORMAL_OPERAND)\n");
PrintSiAddr = 1;
PrintMxcsr = 1;
DoSIMDDenormalizedOperand();
return TSTATUS_NOFAULT;
#else
/* This causes problems on macOS* */
return TSTATUS_SKIP;
#endif
case 28:
printf(" SIMD multiple exceptions\n");
PrintSiAddr = 1;
PrintMxcsr = 1;
DoSIMDMultipleExceptions();
return TSTATUS_NOFAULT;
case 29:
printf(" breakpoint trap (EXCEPTCODE_DBG_BREAKPOINT_TRAP)\n");
DoBreakpointTrap();
return TSTATUS_NOFAULT;
case 30:
printf(" single-step trap (EXCEPTCODE_DBG_SINGLE_STEP_TRAP)\n");
#if 0
/*
* Pin doesn't handle this well now, so it is disabled.
*/
PrintSiAddr = 1;
DoSingleStepTrap();
return TSTATUS_NOFAULT;
#else
return TSTATUS_SKIP;
#endif
case 31:
printf(" bad register encoding\n");
#if !defined(TARGET_BSD)
PrintSiAddr = 1;
DoBadRegister();
return TSTATUS_NOFAULT;
#else
/* This causes problems on BSD. See Mantis #1940 */
return TSTATUS_SKIP;
#endif
case 32:
printf(" put illegal value into segment register gs/fs\n");
#if !defined(TARGET_BSD) && !defined(TARGET_MAC)
PrintSiAddr = 1;
DoIllegalSetOfSegReg1();
return TSTATUS_NOFAULT;
#else
/* This causes problems on BSD. See Mantis #1940 */
return TSTATUS_SKIP;
#endif
case 33:
printf(" illegal mem access in lfs/lgs \n");
#if !defined(TARGET_BSD)
PrintSiAddr = 0;
DoIllegalSetOfSegReg2();
return TSTATUS_NOFAULT;
#else
/* This causes problems on BSD. See Mantis #1940 */
return TSTATUS_SKIP;
#endif
case 34:
printf(" illegal mem access in RW to segment register\n");
#if !defined(TARGET_BSD)
PrintSiAddr = 1;
DoIllegalGetOfSegReg1();
return TSTATUS_NOFAULT;
#else
/* This causes problems on BSD. See Mantis #1940 */
return TSTATUS_SKIP;
#endif
default:
trapNo = tnum - 34;
if (trapNo >= NUM_TRAP_FUNCS)
break;
printf(" INT %u (at %p)\n", trapNo, normalize_addr((intptr_t)&IntTrapCode[trapNo*BYTES_PER_TRAP_FUNC]));
#if defined(TARGET_MAC)
/*
* macOS* kernel delivers all sorts of signals to these traps
*/
if (trapNo <= 5 || trapNo == 127)
return TSTATUS_SKIP;
/*
* These are considered as system calls on macOS*
*/
if (0x80 <= trapNo && trapNo <= 0x83)
return TSTATUS_SKIP;
#else
/*
* Skip 'int 3' because some Linux kernels don't handle it well. See Mantis #666.
* Skip 'int 5' because some Linux kernels don't handle it well. See Mantis #2678.
* Skip 'int 0x80' because it is a system call trap on Linux and BSD.
*/
if (trapNo == 3 || trapNo == 5 || trapNo == 0x80)
return TSTATUS_SKIP;
#endif
PrintSiAddr = 1;
fn = (void (*)(void))&IntTrapCode[trapNo*BYTES_PER_TRAP_FUNC];
fn();
return TSTATUS_NOFAULT;
}
return TSTATUS_DONE;
}
void PrintSignalContext(int sig, const siginfo_t *info, void *vctxt)
{
ucontext_t *ctxt = vctxt;
unsigned long rip;
long int trapno;
long int mxcsr = 0;
long int x87sw = 0;
/*
* Some of the tests set the AC bit. Clear it to prevent alignment-check faults
* while doing the print below.
*/
ClearAC();
#if defined(TARGET_BSD)
rip = (unsigned long)ctxt->uc_mcontext.mc_rip;
trapno = (long int)ctxt->uc_mcontext.mc_trapno;
#elif defined(TARGET_LINUX) && defined(TARGET_IA32E)
rip = (unsigned long)ctxt->uc_mcontext.gregs[REG_RIP];
trapno = (long int)ctxt->uc_mcontext.gregs[REG_TRAPNO];
if (ctxt->uc_mcontext.fpregs)
{
mxcsr = (long int)ctxt->uc_mcontext.fpregs->mxcsr;
x87sw = (long int)ctxt->uc_mcontext.fpregs->swd;
}
#elif defined(TARGET_LINUX) && defined(TARGET_IA32)
rip = (unsigned long)ctxt->uc_mcontext.gregs[REG_EIP];
trapno = (long int)ctxt->uc_mcontext.gregs[REG_TRAPNO];
if (ctxt->uc_mcontext.fpregs)
{
x87sw = (long int)ctxt->uc_mcontext.fpregs->sw;
}
#elif defined(TARGET_MAC) && defined(TARGET_IA32E)
rip = (unsigned long)ctxt->uc_mcontext->__ss.__rip;
trapno = (long int)ctxt->uc_mcontext->__es.__trapno;
mxcsr = (long int)ctxt->uc_mcontext->__fs.__fpu_mxcsr;
#elif defined(TARGET_MAC) && defined(TARGET_IA32)
rip = (unsigned long)ctxt->uc_mcontext->__ss.__eip;
trapno = (long int)ctxt->uc_mcontext->__es.__trapno;
mxcsr = (long int)ctxt->uc_mcontext->__fs.__fpu_mxcsr;
#endif
;
printf(" Signal %d, pc=0x%lx, si_errno=%d, trap_no=%ld",
sig,
normalize_addr((uintptr_t)rip),
(int)info->si_errno,
trapno);
if (!IsBadKernel)
printf(", si_code=%d", (int)info->si_code);
if (PrintSiAddr)
printf(", si_addr=%lx", normalize_addr((uintptr_t)info->si_addr));
if (PrintMxcsr)
printf(", mxcsr=0x%lx", mxcsr);
if (PrintX87Status)
printf(", x87sw=0x%lx", x87sw);
printf("\n");
}