linux - Valgrind और gdb रिकॉर्ड के लिए glibc(LD_HWCAP_MASK,/etc/ld.so.nohwcap) में AVX- अनुकूलित फ़ंक्शन अक्षम करें




linker (2)

मैंने सुना है कि glibc में /etc/ld.so.nohwcap और LD_HWCAP_MASK कॉन्फ़िगरेशन हैं LD_HWCAP_MASK क्या वे glibc में AVX- अनुकूलित स्ट्रिंग फ़ंक्शंस को प्रेषण अक्षम करने के लिए उपयोग किया जा सकता है?

हां: सेटिंग LD_HWCAP_MASK=0 जीएलबीसी को दिखाएगा कि CPU क्षमताओं में से कोई भी उपलब्ध नहीं है। कोड

मुखौटा को 0 पर सेट करना एक त्रुटि को ट्रिगर करने की संभावना है, आपको संभावित रूप से एवीएक्स को नियंत्रित करने वाली सटीक बिट को समझने की आवश्यकता होगी, और उस बिट को ढंकना होगा।

ग्लिबिक के साथ आधुनिक x86_64 लिनक्स यह पता लगाएगा कि सीपीयू ने एवीएक्स विस्तार का समर्थन किया है और जेनेरिक कार्यान्वयन से कई स्ट्रिंग फ़ंक्शंस को एवीएक्स-अनुकूलित संस्करण (ifunc डिस्पैचर्स: 1 , 2 की मदद से) में बदल देगा।

यह सुविधा निष्पादन के लिए अच्छी हो सकती है, लेकिन यह वाल्ग्रिंड ( वाल्ग्रिंड -3.8 से पहले) और जीडीबी के " target record " ( रिवर्स एक्ज़ीक्यूशन ) से सही तरीके से काम करने के लिए वाल्ग्रिंड ( पुराने लिववेएक्स ) जैसे कई टूल को रोकता है (उबंटू "जेड" 17.04 बीटा, जीडीबी 7.12 .50.20170207- 0ubuntu2, जीसीसी 6.3.0-8ubuntu1 20170221, उबंटू जीएलबीसी 2.24-7 बुन्तुु 2):

$ cat a.c
#include <string.h>
#define N 1000
int main(){
        char src[N], dst[N];
        memcpy(dst, src, N);
        return 0;
}
$ gcc a.c -o a -fno-builtin
$ gdb -q ./a
Reading symbols from ./a...(no debugging symbols found)...done.
(gdb) start
Temporary breakpoint 1 at 0x724
Starting program: /home/user/src/a

Temporary breakpoint 1, 0x0000555555554724 in main ()
(gdb) record
(gdb) c
Continuing.
Process record does not support instruction 0xc5 at address 0x7ffff7b60d31.
Process record: failed to record execution log.

Program stopped.
__memmove_avx_unaligned_erms () at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:416
416             VMOVU   (%rsi), %VEC(4)
(gdb) x/i $pc
=> 0x7ffff7b60d31 <__memmove_avx_unaligned_erms+529>:   vmovdqu (%rsi),%ymm4

"लक्ष्य रिकॉर्ड" के जीडीबी के कार्यान्वयन से " Process record does not support instruction 0xc5 " है, क्योंकि एवीएक्स के निर्देश रिकॉर्ड / रीप्ले इंजन (कभी-कभी समस्या को _dl_runtime_resolve_avx फ़ंक्शन पर पाया जाता है) द्वारा समर्थित नहीं होता है: https: // sourceware .org / ml / gdb / 2016-08 / msg00028.html "कुछ AVX निर्देश प्रक्रिया रिकॉर्ड द्वारा समर्थित नहीं हैं", https://bugs.launchpad.net/ubuntu/+source/gdb/+bug/1573786 , https: //bugs.debian.org/cgi-bin/bugreport.cgi?bug=836802 , https://bugzilla.redhat.com/show_bug.cgi?id=1136403

समाधान https://sourceware.org/ml/gdb/2016-08/msg00028.html "में प्रस्तावित कर सकते हैं आप दुबई को फिर से कम्पाइल कर सकते हैं (इस प्रकार ld.so), या __इनट_क्यूपी_फिएक्श हैक करें और इस प्रकार __cpu_features रनटाइम पर (उदाहरण के लिए, स्ट्रक्म्प देखें)।" या LD_BIND_NOW=1 निर्धारित करें, लेकिन पुनः कंपाइल किए गए glibc में अभी भी AVX है, और ld बाँध-अब मदद नहीं करता।

मैंने सुना है कि glibc में /etc/ld.so.nohwcap और LD_HWCAP_MASK कॉन्फ़िगरेशन हैं LD_HWCAP_MASK क्या वे glibc में AVX- अनुकूलित स्ट्रिंग फ़ंक्शंस को प्रेषण अक्षम करने के लिए उपयोग किया जा सकता है?

कैसे glibc (rtld?) /proc/cpuinfo (शायद नहीं) के साथ cpuid का उपयोग AVX का पता लगाता है, या HWCAP aux ( LD_SHOW_AUXV=1 /bin/echo |grep HWCAP आदेश AT_HWCAP: bfebfbff देता है)?


सबसे अच्छा या पूर्ण समाधान नहीं, मेरे कार्य के लिए वाल्ग्रिंड और जीडीबी रिकॉर्ड की अनुमति देने के लिए सिर्फ एक छोटी बिट-संपादन क्लॉज।

Lekensteyn पूछता है :

कैसे glx को recompiling बिना avx / sse बाहर मुखौटा करने के लिए

मैंने पूरी तरह से unmodified glibc का पुनर्निर्माण किया है, जो डेबियन और उबुन्टू में आसान है: सिर्फ sudo apt-get source glibc , sudo apt-get build-dep glibc और cd glibc-*/; dpkg-buildpackage -us -uc cd glibc-*/; dpkg-buildpackage -us -uc (लिड.एस. को छीन लिया डीबगिंग सूचना के बिना मैनुअल

उसके बाद मैंने __get_cpu_features द्वारा उपयोग किए गए फ़ंक्शन में, आउटपुट ld.so फ़ाइल के द्विआधारी (बिट) पैचिंग किया। लक्ष्य फ़ंक्शन को get_common_indeces के नाम के तहत स्रोत फ़ाइल sysdeps/x86/cpu-features.c के get_common_indeces से संकलित किया गया था (यह बाइनरी कोड में __get_cpu_features के __get_cpu_features बाद है)। इसमें कई सीपीयू हैं, पहले cpuid eax=1 ईएक्स cpuid eax=1 "प्रोसेसर इन्फो और फीचर बिट्स" ; और बाद में "जेले 0x6" की जांच हो रही है और एवीएक्स 2 स्थिति पाने के लिए कोड " cpuid eax=7 ecx=0 विस्तारित सुविधाएँ" के चारों ओर कूदें। कोड है जो इस तर्क में संकलित किया गया था:

get_common_indeces (struct cpu_features *cpu_features,
            unsigned int *family, unsigned int *model,
            unsigned int *extended_model, unsigned int *stepping)
{ ...
  if (cpu_features->max_cpuid >= 7)
    __cpuid_count (7, 0,
           cpu_features->cpuid[COMMON_CPUID_INDEX_7].eax,
           cpu_features->cpuid[COMMON_CPUID_INDEX_7].ebx,
           cpu_features->cpuid[COMMON_CPUID_INDEX_7].ecx,
           cpu_features->cpuid[COMMON_CPUID_INDEX_7].edx);

cpu_features->max_cpuid __cpuid (0, cpu_features->max_cpuid, ebx, ecx, edx); में एक ही फाइल के cpu_features->max_cpuid में भर गया था __cpuid (0, cpu_features->max_cpuid, ebx, ecx, edx); लाइन। jle cmp 0x6 बाद jg (बाइट 0x7e से 0x7f) के साथ jle को स्थानांतरित करके if स्टेटमेंट को अक्षम करना आसान था। (असल में इस द्विआधारी पैच को वास्तविक प्रणाली के __get_cpu_features फ़ंक्शन के लिए मैन्युअल रूप से पुन: लागू किया गया था ld-linux.so.2 - पहले mov 7 eax; xor ecx,ecx; cpuid मिनट में पहले jle mov 7 eax; xor ecx,ecx; cpuid jg में बदल गया।)

Recompiled पैकेज और संशोधित ld.so सिस्टम में स्थापित नहीं थे; मैंने ld.so ./my_program (या mv ld.so /some/short/path.so और patchelf --set-interpreter ./my_program ) के कमांडलाइन सिंटैक्स का उपयोग किया है।

अन्य संभावित समाधान:

  • अधिक हाल के valgrind और gdb रिकॉर्ड उपकरण का उपयोग करने का प्रयास करें
  • पुराने glibc का उपयोग करने की कोशिश करो
  • जीडीबी रिकॉर्ड में लापता अनुदेश अनुकरण को लागू करें यदि यह नहीं किया गया है
  • if (cpu_features->max_cpuid >= 7) कोड को चारों ओर पैचिंग करना if (cpu_features->max_cpuid >= 7) glibc और recompile में
  • glibc और recompile में avx2- सक्षम स्ट्रिंग फ़ंक्शंस के चारों ओर स्रोत कोड पैचिंग करना