1 2.globl _start 3 4_start: 5 # This code tests for the fldcw "load floating point command word" 6 # instruction. On most x86 processors the retired_instruction 7 # performance counter counts this as one instruction. However, 8 # on Pentium 4 systems it counts as two. Therefore this can 9 # affect BBV results on such a system. 10 # fldcw is most often used to set the rouding mode when doing 11 # floating point to integer conversions 12 13 # It is encoded as "d9 /5" which means 14 # 1101 1001 xx10 1yyy 15 # Where xx is the "mod" which will be 00, 01, or 10 indicating offset 16 # and yyy is the register field 17 18 19 20 # these are instructions with similar encodings to fldcw 21 # that can cause false positives if the test isn't explicit enough 22similar: 23 fld1 # d9 e8 24 fldl2t # d9 e9 25 fldl2e # d9 ea 26 fldpi # d9 eb 27 fldlg2 # d9 ec 28 fldln2 # d9 ed 29 fldz # d9 ee 30 31 # check some varied ways of calling fldcw 32 33 34 # offset on stack 35stack: 36 sub $4,%esp # allocate space on stack 37 fnstcw 2(%esp) 38 fldcw 2(%esp) 39 add $4,%esp # restore stack 40 41 # 32-bit register 42 43 fnstcw cw 44 mov $cw,%eax 45 fldcw 0(%eax) # eax 46 mov $cw,%ebx 47 fldcw 0(%ebx) # ebx 48 mov $cw,%ecx 49 fldcw 0(%ecx) # ecx 50 mov $cw,%edx 51 fldcw 0(%edx) # edx 52 53 # register + 8-bit offset 54eight_bit: 55 mov $cw,%eax 56 sub $32,%eax 57 58 fldcw 32(%eax) # eax + 8 bit offset 59 mov %eax,%ebx 60 fldcw 32(%ebx) # ebx + 8 bit offset 61 mov %eax,%ecx 62 fldcw 32(%ecx) # ecx + 8 bit offset 63 mov %eax,%edx 64 fldcw 32(%edx) # edx + 8 bit offset 65 66 # register + 32-bit offset 67thirtytwo_bit: 68 mov $cw,%eax 69 sub $30000,%eax 70 71 fldcw 30000(%eax) # eax + 16 bit offset 72 mov %eax,%ebx 73 fldcw 30000(%ebx) # ebx + 16 bit offset 74 mov %eax,%ecx 75 fldcw 30000(%ecx) # ecx + 16 bit offset 76 mov %eax,%edx 77 fldcw 30000(%edx) # edx + 16 bit offset 78 79 # check an fp/integer conversion 80 # in a loop to give a bigger count 81 82 mov $1024,%ecx 83big_loop: 84 85 fldl three # load value onto fp stack 86 fnstcw saved_cw # store control word to mem 87 movzwl saved_cw, %eax # load cw from mem, zero extending 88 movb $12, %ah # set cw for "round to zero" 89 movw %ax, cw # store back to memory 90 fldcw cw # save new rounding mode 91 fistpl result # save stack value as integer to mem 92 fldcw saved_cw # restore old cw 93 94 loop big_loop # loop to make the count more obvious 95 96 movl result, %ebx # sanity check to see if the 97 cmp $3,%ebx # result is the expected one 98 je exit 99 100print_error: 101 mov $4,%eax # write syscall 102#if defined(VGO_darwin) 103 pushl $22 104 pushl $error 105 pushl $1 106 int $0x80 107#elif defined(VGO_linux) 108 mov $1,%ebx # stdout 109 mov $error,%ecx # string 110 mov $22,%edx # length of string 111 int $0x80 112#elif defined(VGO_solaris) 113 pushl $22 114 pushl $error 115 pushl $1 116 int $0x91 117#else 118# error "Unknown OS" 119#endif 120 121exit: 122 movl $1, %eax # SYSCALL_EXIT 123#if defined(VGO_darwin) 124 pushl result 125 int $0x80 126#elif defined(VGO_linux) 127 movl result, %ebx # load converted value 128 int $0x80 129#elif defined(VGO_solaris) 130 pushl result 131 int $0x91 132#else 133# error "Unknown OS" 134#endif 135 136 137.data 138saved_cw: .long 0 139cw: .long 0 140result: .long 0 141three: .long 0 # a floating point 3.0 142 .long 1074266112 143error: .ascii "Error! Wrong result!\n\0" 144