2015-05-19 32 views
1

的CentOS 6.5 64位VPS,500MB RAM GCC 4.8.2爲什麼在這個內聯彙編中需要使用edi約束?

我有以下功能僅適用如果我使用EDI作爲約束來保存字符串指針。如果我嘗試使用任何其他寄存器或約束gq等,它會發生段錯誤。

但是隻有當鏈接時間優化和o3一起使用時纔會出現此問題。如果o2沒關係。如果我不使用-flto,那很好。但是,兩者一起,那麼唯一的註冊,我可以使用不崩潰是edi

gcc -flto 
CFLAGS=-I. -flto -std=gnu11 -msse4.2 -fno-builtin-printf -Wall -Winline -Wstrict-aliasing -g -pg -O3 -lrt -lpthread 

好像有可能是某種寄存器重挫事情還是其他什麼東西的。我真的很難理解爲什麼以及如何解決這個問題。另一個有趣的方面是生成的程序集使用指針之前將rdi放入rdx,但如果我嘗試使用任一寄存器作爲輸入約束......它會發生段錯誤!如果它在積極的編譯選項下失敗,它向我暗示編譯器會以某種方式填塞,或者更可能是我做錯了什麼。

char *sse4_strCRLF(char *str) 
    { 
    __m128i M = _mm_set1_epi8(13); 
    char *res; 
    __asm__ __volatile__(
    "xor %0,%0\n\t" 
    "sub $1, %1\n\t" 
"1:" "sub $15,%1\n\t" 
    ".align 16\n\t" 
"2:" "add $16, %1\n\t" 
    "pcmpistri $0x08,(%1),%2\n\t" 
    "ja 2b\n\t" 
    "jnc 2f\n\t" 

    "cmpb $10,1(%1,%%rcx)\n\t" 
    "jne 1b\n\t" 
    "add %%rcx,%1\n\t" 
    "mov %1,%0\n\t" 
"2:" 
    :"=q"(res) 
    :"edi"(str),"x"(M) //<-- if use anything except edi, it segfaults 
    :"rcx" 
    ); 
return (char*) res; 
} 

拆輸出:

00000000000002e0 <sse4_strCRLF>: 
2e0: 55      push rbp 
2e1: 48 89 e5    mov rbp,rsp 
2e4: e8 00 00 00 00   call 2e9 <sse4_strCRLF+0x9> 
2e9: 66 0f 6f 05 00 00 00 00 movdqa xmm0,[rip+0x0]   # 2f1 <sse4_strCRLF+0x11> 
2f1: 48 89 fa    mov rdx,rdi //<--- puts rdi into rdx! 
2f4: 48 31 c0    xor rax,rax 
2f7: 48 83 ea 01    sub rdx,0x1 
2fb: 48 83 ea 0f    sub rdx,0xf 
2ff: 90      nop 
300: 48 83 c2 10    add rdx,0x10 
304: 66 0f 3a 63 02 08  pcmpistri xmm0,[rdx],0x8 
30a: 77 f4     ja  300 <sse4_strCRLF+0x20> 
30c: 73 0d     jae 31b <sse4_strCRLF+0x3b> 
30e: 80 7c 0a 01 0a   cmp byte[rdx+rcx*1+0x1],0xa 
313: 75 e6     jne 2fb <sse4_strCRLF+0x1b> 
315: 48 01 ca    add rdx,rcx 
318: 48 89 d0    mov rax,rdx 
31b: 5d      pop rbp 
31c: c3      ret 
+1

我不認爲「edi」是指你認爲它的作用。查看[docs](https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html)(向下滾動到x86系列):「e」表示「32位有符號整數常量」,「d 「表示rdx寄存器,」i「表示」立即整型操作數「。通過指定所有3,您允許編譯器在這3個選項中進行選擇,而不是(因爲我懷疑您打算)選擇edi寄存器。 –

+1

另一個重要點:正如[docs](https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#InputOperands)所說,您不得修改輸入參數。 –

+0

我不知道禁止修改輸入參數!我認爲這會解決它,但唉。我改變了代碼,以便%1被移入一個寄存器,所有操作都在該寄存器上完成,但仍然是相同的問題 – poby

回答

1

@大衛Wohlferd給我的回答。由於無知和假設,我犯了兩個愚蠢的錯誤。下面的代碼被修改,使得輸入變量char指針不會被例程修改。它被複制到一個寄存器中並使用該寄存器。我也錯誤地認爲我可以直接指定一個特定的寄存器,而不是ab

gcc似乎仍然對我用什麼約束很挑剔。例如如果我分別使用ab分別爲resstr,它會在運行時編譯好但是段錯誤。但使用SD似乎工作正常。

@David Wohlferd,我想讚揚你作爲回答者,但我不認爲我可以這樣評論。

char *sse4_strCRLF(char *str) 
    { 
    __m128i M = _mm_set1_epi8(13); 
    char *res; 
    __asm__ __volatile__(
    "xor %0,%0\n\t" 
    "mov %1,%%rdx\n\t" 
    "sub $1,%%rdx\n\t" 
"1:" "sub $15,%%rdx\n\t" 
    ".align 16\n\t" 
"2:" "add $16, %%rdx\n\t" 
    "pcmpistri $0x08,(%%rdx),%2\n\t" 
    "ja 2b\n\t" 
    "jnc 2f\n\t" 

    "cmpb $10,1(%%rdx,%%rcx)\n\t" 
    "jne 1b\n\t" 
    "add %%rcx,%%rdx\n\t" 
    "mov %%rdx,%0\n\t" 
"2:" 
    :"=S"(res) 
    :"D"(str),"x"(M) 
    :"rcx","rdx" 
    ); 
    return (char*) res; 
} 
+0

這可能寫得更好。我擔心只是假設rcx將包含str。即使你正在訪問內存,也不使用內存clobber。但是,如果你對它感到滿意...... –

+0

我的確在某處讀過pcmpistri在rcx中返回結果,所以這次我沒有做出假設。而且我不認爲我在這裏修改記憶,所以我不認爲記憶破壞是一個問題。如果我錯了,請告訴我。我還在學習。 – poby

+0

我相信有一個更優雅的方式來寫它,但它的性能寫。就像將普通循環裝入緩存行等一樣。如果有辦法讓速度更快,我很樂意聽到它。 – poby

相關問題