2011-08-14 15 views
15

एक कंपाइलर प्रोजेक्ट के हिस्से के रूप में मुझे फ़्लोटिंग पॉइंट मानों की तुलना करने के लिए x86 के लिए जीएनयू असेंबलर कोड लिखना होगा। मैंने इस ऑनलाइन तरीके से संसाधनों को खोजने का प्रयास किया है और जो मैं समझता हूं उससे यह काम करता है:x86 असेंबलर: फ़्लोटिंग पॉइंट की तुलना

मानों को मानना ​​जो मैं तुलना करना चाहता हूं वो फ़्लोटिंग पॉइंट स्टैक पर एकमात्र मान हैं, फिर fcomi निर्देश की तुलना की जाएगी मान और सीपीयू-झंडे सेट करें ताकि je, jne, jl, ... निर्देशों का उपयोग किया जा सके।

मैं पूछ रहा हूं क्योंकि यह कभी-कभी काम करता है। उदाहरण के लिए:

.section .data 
msg: .ascii "Hallo\n\0" 
f1:  .float 10.0 
f2:  .float 9.0 

.globl main 
    .type main, @function 
main: 
    flds f1 
    flds f2 
    fcomi 
    jg leb 
    pushl $msg 
    call printf 
    addl $4, %esp 
leb: 
    pushl $0 
    call exit 

"Hallo" प्रिंट होगा नहीं भले ही मुझे लगता है कि यह होना चाहिए, और यदि आप F1 और F2 स्विच यह अभी भी जो एक तार्किक विरोधाभास नहीं है जाएगा। je और jne हालांकि ठीक काम करने लगते हैं।

मैं क्या गलत कर रहा हूं?

पीएस: क्या fcomip पॉप केवल एक मान है या यह दोनों पॉप करता है?

उत्तर

34

यह सब Intel 64 and IA-32 Architectures Software Developer's Manuals के वॉल्यूम 2 ​​से आ रहा है।

FCOMI सेट झंडे कि CMP करता है की केवल कुछ। आपके कोड में %st(0) == 9 और %st(1) == 10 है। (चूंकि यह एक स्टैक है जिसे वे लोड कर रहे हैं), वॉल्यूम 2 ​​ए में पेज 3-348 पर तालिका का जिक्र करते हुए आप देख सकते हैं कि यह "एसटी 0 < एसटी (i)" है, इसलिए यह जेडएफ और पीएफ और सेट को साफ़ करेगा सीएफ़ इस बीच पीजी पर। 3-544 वॉल्यूम 2 ए आप पढ़ सकते हैं कि JG का अर्थ है "अधिक से अधिक कूदें (ZF = 0 और SF = OF)"। दूसरे शब्दों में यह साइन, ओवरफ्लो और शून्य झंडे का परीक्षण कर रहा है, लेकिन FCOMI साइन या ओवरफ़्लो सेट नहीं करता है!

आप किन स्थितियों पर कूदना चाहते हैं, इस पर निर्भर करते हुए, आपको संभावित तुलना परिणामों को देखना चाहिए और तय करना चाहिए कि आप कब कूदना चाहते हैं।

 
+--------------------+---+---+---+ 
| Comparison results | Z | P | C | 
+--------------------+---+---+---+ 
| ST0 > ST(i)  | 0 | 0 | 0 | 
| ST0 < ST(i)  | 0 | 0 | 1 | 
| ST0 = ST(i)  | 1 | 0 | 0 | 
+--------------------+---+---+---+ 

मैं यह आसान यह पता लगाने की बनाने के लिए इस छोटी सी मेज कर दिया है:

 
+--------------+---+---+-----+------------------------------------+ 
| Test   | Z | C | Jcc | Notes        | 
+--------------+---+---+-----+------------------------------------+ 
| ST0 < ST(i) | X | 1 | JB | ZF will never be set when CF = 1 | 
| ST0 <= ST(i) | 1 | 1 | JBE | Either ZF or CF is ok    | 
| ST0 == ST(i) | 1 | X | JE | CF will never be set in this case | 
| ST0 != ST(i) | 0 | X | JNE |         | 
| ST0 >= ST(i) | X | 0 | JAE | As long as CF is clear we are good | 
| ST0 > ST(i) | 0 | 0 | JA | Both CF and ZF must be clear  | 
+--------------+---+---+-----+------------------------------------+ 
Legend: X: don't care, 0: clear, 1: set 

दूसरे शब्दों में हालत कोड अहस्ताक्षरित तुलना प्रयोग करने के लिए मेल खाते हैं। वही होता है यदि आप FMOVcc का उपयोग कर रहे हैं।

तो fcomi के लिए या तो (या दोनों) संकार्य NaN है, यह ZF=1 PF=1 CF=1 सेट। (एफपी तुलनाओं में 4 संभावित परिणाम हैं: >, <, ==, या असाधारण)। यदि आपको परवाह है कि आपका कोड NaNs के साथ क्या करता है, तो आपको अतिरिक्त jp या jnp की आवश्यकता हो सकती है। लेकिन हमेशा नहीं: उदाहरण के लिए, ja केवल तभी सच है जब सीएफ = 0 और जेडएफ = 0, तो यह अनियंत्रित मामले में नहीं लिया जाएगा। यदि आप अनियंत्रित मामले को नीचे या बराबर के समान निष्पादन पथ लेना चाहते हैं, तो ja आपको केवल इतना ही चाहिए।


यहाँ आप JA का उपयोग करना चाहिए, यदि आप इसे प्रिंट करना चाहते हैं (यानी। if (!(f2 > f1)) { puts("hello"); }) और JBE यदि आप नहीं (if (!(f2 <= f1)) { puts("hello"); } से मेल खाती है)। (ध्यान दें कि इस तथ्य के कारण यह थोड़ा उलझन में हो सकता है कि अगर हम कूद नहीं पाते हैं तो हम केवल प्रिंट करते हैं)।


अपने दूसरे प्रश्न के बारे में: डिफ़ॉल्ट fcomi द्वारा कुछ भी पॉप नहीं करता है। आप इसके करीबी चचेरे भाई fcomip चाहते हैं जो %st0 पॉप करता है। उपयोग के बाद आपको हमेशा एफपीयू रजिस्टर स्टैक को साफ़ करना चाहिए, इसलिए आपके सभी कार्यक्रमों में यह सब खत्म हो गया है कि आप संदेश मुद्रित करना चाहते हैं:

.section .rodata 
msg: .ascii "Hallo\n\0" 
f1:  .float 10.0 
f2:  .float 9.0 

.globl main 
    .type main, @function 
main: 
    flds f1 
    flds f2 
    fcomip 
    fstp %st(0) # to clear stack 
    ja  leb # won't jump, jbe will 
    pushl $msg 
    call printf 
    addl $4, %esp 
leb: 
    pushl $0 
    call exit 
+7

बहुत प्रभावशाली उत्तर। बकाया। एक मामूली टिप्पणी: 'ja 'के विपरीत' jbe' है, 'jb' नहीं। –

+2

@ रे टोल: आप बिल्कुल सही हैं। हालांकि इस मामले में इससे कोई फर्क नहीं पड़ता है, मैंने उदाहरण बदल दिया क्योंकि यह इस तरह से अधिक समझ में आता है। – user786653

+0

अच्छा! बहुत धन्यवाद! – JustMaximumPower