2017-09-25 42 views
0

我想在C++中實現Intel DRNG英特爾DRNG給只給4字節的數據而不是8

根據它的引導,以產生64位無符號長長的代碼應該是:

int rdrand64_step (unsigned long long *rand) 
{ 
    unsigned char ok; 
    asm volatile ("rdrand %0; setc %1" 
        : "=r" (*rand), "=qm" (ok)); 
    return (int) ok; 
} 

然而該函數rand的輸出僅給我只有32位的輸出,如圖所示。

 bd4a749d 
     d461c2a8 
     8f666eee 
     d1d5bcc4 
     c6f4a412 

爲什麼會出現這種情況?

更多信息:我使用的IDE是代碼塊

+0

在哪個操作系統上,哪個版本的C++和哪個編譯器? C++ 11有[''](http://en.cppreference.com/w/cpp/numeric/random),更好地使用它(因爲它是可移植的)。 [Code :: Blocks](http://www.codeblocks.org/)不是*編譯器(它運行一個,也許是[GCC](http://gcc.gnu.org/)),而是一個IDE –

+0

***我使用的編譯器是codeblocks *** Code :: Blocks是一個IDE。我假設編譯器是mingw的某個版本。 – drescherjm

+0

Linux有'/ dev/random'參見[random(4)](http://man7.org/linux/man-pages/man4/random.4.html),[mingw](http:// mingw .org /)是 - 或者包含 - [GCC]的端口(http://gcc.gnu.org/)。在終端中運行'g ++ -v'或'g ++ --version'。最近足夠的mingw應該提供一個C++ 11編譯器 –

回答

3

immintrin.h,而不需要編寫內聯彙編使用int _rdrand64_step (unsigned __int64* val)。你不需要它,有很多原因(包括本),以避免它:https://gcc.gnu.org/wiki/DontUseInlineAsm


在這種情況下,問題是,你可能編譯32位代碼,所以當然64位rdrand是不可編碼的。但是你使用inline-asm的方式最終會給你一個32位的rdrand,並在另一個寄存器中存儲垃圾。

gcc -Wall -O3 -m32 -march=ivybridge(和鐺類似)產生(on Godbolt):

In function 'rdrand64_step': 
7 : <source>:7:1: warning: unsupported size for integer register 

rdrand64_step: 
    push ebx 
    rdrand ecx; setc al 
    mov  edx, DWORD PTR [esp+8] # load the pointer arg 
    movzx eax, al 
    mov  DWORD PTR [edx], ecx 
    mov  DWORD PTR [edx+4], ebx # store garbage in the high half of *rand 
    pop  ebx 
    ret 

我猜你叫與碰巧有ebx=0呼叫者此功能。否則你使用了一個不同的編譯器來做一些不同的事情。內聯後可能會發生其他事情。如果你看看反彙編你實際編譯的內容,你可以解釋到底發生了什麼。


如果你使用的內在,你會得到error: '_rdrand64_step' was not declared in this scope,因爲只有immintrin.h宣佈它在64位模式(並與-march設置,意味着rdrand支持。或者[-mrdrnd] 3。最佳選項:使用-march=native如果您正在目標機器上構建)。

您也會得到顯著更有效的代碼爲重試循環,至少鏗鏘:

unsigned long long use_intrinsic(void) { 
    unsigned long long rand; 
    while(!_rdrand64_step(&rand)); // TODO: retry limit in case RNG is broken. 
    return rand; 
} 

use_intrinsic:       # @use_intrinsic 
.LBB2_1:        # =>This Inner Loop Header: Depth=1 
    rdrand rax 
    jae  .LBB2_1 
    ret 

這避免了setcc,然後測試的是,這當然是多餘的。 gcc6具有用於從內聯asm返回標誌結果的語法。您也可以使用asm goto並在asm中放置一個jcc,跳轉到label: return 1;目標或落入return 0。 (。內聯彙編文檔有這樣https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html的例子也the inline-assembly tag wiki見)

使用您的內聯彙編,鐺(在64位模式),它編譯於:

use_asm: 
.LBB1_1: 
    rdrand rax 
    setb byte ptr [rsp - 1] 
    cmp  byte ptr [rsp - 1], 0 
    je  .LBB1_1 
    ret 

(鏗鏘對包含內存在內的多個選項的約束做出錯誤的決定。)

gcc7.2和ICC17實際上最終得到了比asm更好的代碼。他們使用cmovc得到0或1,然後test。這很愚蠢。但這是一個gcc/ICC未能優化,希望是。

+0

是的,它似乎我使用的是32位編譯器,我試圖改變使用[minGW64](https://stackoverflow.com/questions/26414511/how-do-i-compile-for-64bit-using-gw- codeblocks)但當我測試運行它使用'cout <<「sizeof(void *)=」<< sizeof(void *)<<「;」 << endl;'我得到4而不是預期的[8](http://wiki.codeblocks.org/index.php/64Bit_Windows)並使用我的代碼,我仍然只獲得32位返回。它是因爲我的IDE是32位的? – albusSimba

+0

@albusSimba:如果默認值爲「-m32」,則IDE必須傳遞「-m64」。 IDK關於IDE的任何內容,但沒有理由說32位進程在運行64位可執行文件時會遇到麻煩。它不會加載編譯器作爲庫(是嗎?) –

+0

是的,我有ALR傳遞'-m64',但它仍然不會通過'cout <<「sizeof(void *)=」<< sizeof(void *)<<「;」 << endl;'這意味着它仍在32位上運行 – albusSimba

相關問題