簡體   English   中英

在 MacOS 上編譯 c++ 和匯編代碼時架構 arm64 的未定義符號

[英]Undefined symbols for architecture arm64 when compiling c++ and assembly code on MacOS

我正在閱讀這本書的 ARM64 程序集,有一章你必須從 c++ 調用匯編代碼。

每次我編譯它我都會收到這個錯誤

Undefined symbols for architecture arm64:
  "_IntegerAddSubA_", referenced from:
      _main in main-11e536.o
  "_IntegerAddSubB_", referenced from:
      _main in main-11e536.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

主.cpp

#include <iostream>

using namespace std;

extern "C" int IntegerAddSubA_(int a, int b, int c);
extern "C" long IntegerAddSubB_(long a, long b, long c);

template <typename T>
void PrintResult(const char* msg, T a, T b, T c, T result){
    const char nl = '\n';
    
    cout << msg << nl;
    cout << "a" << a << nl;
    cout << "b" << b << nl;
    cout << "c" << c << nl;
    cout << "result (a + b + c) = " << result << nl;
    cout << nl;
}

int main(int argc, const char * argv[]) {
    int a1 = 100, b1 = 200, c1 = -50, result1;
    result1 = IntegerAddSubA_(a1, b1, c1);
    PrintResult("IntergerAddSubA_", a1, b1, c1, result1);
    
    long a2 = 1000, b2 = -2000, c2 = 500, result2;
    result2 = IntegerAddSubB_(a2, b2, c2);
    PrintResult("IntegerAddSubB_", a2, b2, c2, result2);
    return 0;
}

CH.S

    .text
    .global IntegerAddSubA_
    .align 2

IntegerAddSubA_:
    add W3,W0,W1
    sub W0,W3,W2
    ret

.global IntegerAddSubB_

IntegerAddSubB_:
    add X3,X0,X1
    sub X0,X3,X2
    ret

我嘗試先將匯編代碼編譯成一個 object 文件,但似乎沒有任何效果。

如前所述,您必須將前導“_”添加到程序集文件中的符號名稱。 這只是您對 C 語言的實現在 ARM64 上(在體系結構和操作系統的各種組合上)所做的事情。

最好避免匯編源代碼的另一個原因。 通過像這樣使用內聯 asm 可以大大改進代碼:

int IntegerAddSubA_(int a, int b, int c) {
    int r, t;
    asm("add %w[t], %w[a], %w[b]\n"
        "sub %w[r], %w[t], %w[c]"
        : [r] "=r" (r), [t] "=&r" (t)
        : [a] "%r" (a), [b] "r" (b), [c] "r" (c)
        : );
    return r;
}

Output 操作數: r是最終結果,可能與輸入重疊。 t也被寫入並且可能不會與任何輸入寄存器重疊。

輸入操作數:對於 ARM64 上的所有重要事項, ab可交換( a+b == b+a )。

Clobber:什么都沒有被破壞。 Memory 沒有改變。

編譯成這個:

IntegerAddSubA_(int, int, int):                 // @IntegerAddSubA_(int, int, int)
        add     w8, w0, w1
        sub     w0, w8, w2
        ret

最大的區別是編譯器將內聯此代碼,然后選擇可用的或已經保存值的寄存器。 它避免了為一些簡單的事情(例如一些 asm 指令)而不得不洗牌寄存器和進行昂貴的 function 調用。

我建議僅在具有復雜功能時才使用匯編源文件。

int foo(int a1, int b1, int c1, int a2, int b2, int c2) {
    return IntegerAddSubA_(a1, b1, c1) + IntegerAddSubA_(a2, b2, c2);
}

foo(int, int, int, int, int, int):                           // @foo(int, int, int, int, int, int)
        add     w9, w0, w1
        sub     w8, w9, w2
        add     w10, w3, w4
        sub     w9, w10, w5
        add     w0, w9, w8
        ret

請注意 IntegerAddSubA_ 的 2 個內聯版本如何使用 arguments 已經存在的寄存器並使用不同的臨時和結果寄存器,從而不會浪費操作碼。

暫無
暫無

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

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