簡體   English   中英

GCC內聯匯編中的一個簡單while循環

[英]A simple while-loop in GCC inline assembly

我想使用GCC擴展內聯ASM編寫以下循環:

long* arr = new long[ARR_LEN]();
long* act_ptr = arr;
long* end_ptr = arr + ARR_LEN;

while (act_ptr < end_ptr)
{
    *act_ptr = SOME_VALUE;
    act_ptr += STEP_SIZE;
}

delete[] arr;

分配長度為ARR_LEN long類型的數組,並將其初始化為零。 循環以STEP_SIZE的增量STEP_SIZE數組。 每個觸摸的元素都設置為SOME_VALUE

好吧,這是我第一次在GAS中嘗試:

long* arr = new long[ARR_LEN]();

asm volatile
(
    "loop:"
    "movl %[sval], (%[aptr]);"
    "leal (%[aptr], %[incr], 4), %[aptr];"
    "cmpl %[eptr], %[aptr];"
    "jl loop;"
    : // no output
    : [aptr] "r" (arr),
      [eptr] "r" (arr + ARR_LEN),
      [incr] "r" (STEP_SIZE),
      [sval] "i" (SOME_VALUE)
    : "cc", "memory"
);

delete[] arr;

如注釋中所述,確實,此匯編代碼更像是do {...} while循環,但實際上它執行相同的工作。

那段代碼的真正奇怪之處在於,一開始它對我來說效果很好。 但是當我后來試圖使其在另一個項目中工作時,似乎似乎什么也做不了。 我什至制作了工作項目的1:1副本,再次進行編譯,...結果仍然是隨機的。

也許我對輸入​​操作數使用了錯誤的約束,但是到目前為止,我實際上已經嘗試了幾乎所有輸入操作數,而且我還沒有真正的想法。 特別令我困惑的是,它在某些情況下仍然有效。

盡管我在上大學時就已經學過,但我並不是ASM的專家。 請注意,我不是在尋求優化-我只是想了解內聯匯編的工作方式。 所以這是我的問題:我的嘗試有根本性的錯誤嗎?還是我在這里犯了一個更細微的錯誤? 提前致謝。

(使用g ++ MinGW Win32 x86 v.4.8.1)

更新資料

到目前為止,我已經嘗試了所有在此提出的建議。 我特別嘗試過

  • 使用“ q”操作數約束而不是“ r”,有時會起作用,有時卻不起作用,
  • ... : [aptr] "=r" (arr) : "0" (arr) ...相反,相同的結果,
  • 甚至... : [aptr] "+r" (arr) : ...仍然相同。

同時,我非常了解官方文檔 ,但仍然看不到我的錯誤。

您正在修改不允許的輸入操作數( aptr )。 約束它與輸出操作數匹配或將其更改為輸入/輸出操作數。

這是具有預期行為的完整代碼。

  • 請注意,該代碼是為64位計算機編寫的。 因此,例如使用%%rbx代替%%ebx作為陣列的基地址。 出於相同的原因,應使用leaqcmpq代替lealcmpl
  • 由於數組的類型為long應使用movq
  • 在64位計算機上, long類型是8字節而不是4字節。
  • 問題中的jl應該更改為jg
  • 不能使用寄存器標簽,因為編譯器將使用所選寄存器的32位版本(例如ebx )替換它們。
  • 不能使用約束"r" "r"表示可以使用任何寄存器,但是leaq不能接受任何寄存器組合。 在這里看: x86尋址模式

     #include <iostream> using namespace std; int main(){ int ARR_LEN=20; int STEP_SIZE=2; long SOME_VALUE=100; long* arr = new long[ARR_LEN]; int i; for (i=0; i<ARR_LEN; i++){ arr[i] = 0; } __asm__ __volatile__ ( "loop:" "movq %%rdx, (%%rbx);" "leaq (%%rbx, %%rcx, 8), %%rbx;" "cmpq %%rbx, %%rax;" "jg loop;" : // no output : "b" (arr), "a" (arr+ARR_LEN), "c" (STEP_SIZE), "d" (SOME_VALUE) : "cc", "memory" ); for (i=0; i<ARR_LEN; i++){ cout << "element " << i << " is " << arr[i] << endl; } delete[] arr; return 0; } 

對於x86和x64都有效的答案如何(盡管它確實假設long始終為4字節,例如Windows)? OP的主要更改是使用“ + r”和(溫度)。

#include <iostream>

using namespace std;

int main(){

  int ARR_LEN=20;
  size_t STEP_SIZE=2;
  long SOME_VALUE=100;

  long* arr = new long[ARR_LEN];

  for (int i=0; i<ARR_LEN; i++){
    arr[i] = 0;
  }

  long* temp = arr;

   asm volatile (
      "loop:\n\t"
      "movl %[sval], (%[aptr])\n\t"
      "lea (%[aptr], %[incr], %c[size]), %[aptr]\n\t"
      "cmp %[eptr], %[aptr]\n\t"
      "jl loop\n\t"
      : [aptr] "+r" (temp)
      : [eptr] "r" (arr + ARR_LEN),
        [incr] "r" (STEP_SIZE),
        [sval] "i" (SOME_VALUE),
        [size] "i" (sizeof(long))
      : "cc", "memory"
   );

  for (int i=0; i<ARR_LEN; i++){
    cout << "element " << i << " is " << arr[i] << endl;
  }

  delete[] arr;

  return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM