16

PowerPC ブランチはターゲット オフセットに 24 ビットしか使用できないため、テキスト セクションが大きくなりすぎると、一方の端のブランチが他方のターゲットに到達できなくなります。より遠くのターゲットに到達できる長い命令シーケンスがあります (オフセットは 24 ビットではなく 32 ビットです) が、-mlongcallオプションを渡さない限り、GCC はデフォルトでそれを使用しません。ただし、このオプションをオンにしても、GCC は特定の関数の短い呼び出しを生成しますoperator newoperator delete

たとえば、次のコードがあるとします。

extern void foo();

int main(int argc, char** argv) {
    foo();
    new char;
}

GCC を通常実行すると、アセンブリが生成されます。

bl _Z3foov // void foo()
bl _Znwj   // operator new(unsigned int)

オプションを指定して GCC を実行すると、-mlongcall以下が生成されます。

lis r9, _Z3foov@ha
addi r9, r9, _Z3foov@l
mtctr r9
bctrl
bl _Znwj

foo()予想どおり、最初の 4 つの命令は への長い呼び出しですが、への呼び出しoperator newは変更されていません。ランダムな libc および libstdc++ 関数への呼び出しはすべて、予想どおり長い呼び出しに変換されます。operator newdoとcall がまだ指示operator deleteとして終わるのはなぜですか? blGCCに長い呼び出しを強制する方法はありますか? 64 ビットの PowerPC Fedora マシンで GCC 4.7.2 を使用しています (ただし、32 ビットをビルドしています)。

4

2 に答える 2

3

g++ ツールチェーンには、アーキテクチャ上で C++ 標準ライブラリの 8 つの「置換可能な」関数を呼び出す方法に何らかのバグがあるようです (これらの関数が実際にユーザー コードに置き換えられていない場合)。

8 つすべての移植可能な代替実装は次のとおりです。

#include <memory>
#include <cstdlib>

// May never return a null pointer.
void* operator new(std::size_t size) {
    void* p = std::malloc(size, 1);
    while (!p) {
        std::new_handler handler = std::get_new_handler();
        if (handler) {
            handler();
        } else {
            throw std::bad_alloc();
        }
        // A handler is only allowed to return if it did something to make more
        // memory available, so try again.
        p = std::malloc(size, 1);
    }
    return p;
}

void operator delete(void* p) noexcept {
    if (p) std::free(p);
}

void* operator new(std::size_t size, const std::nothrow_t&) noexcept {
    void* p = nullptr;
    try {
        p = operator new(size);
    } catch(...) {}
    return p;
}

void operator delete(void* p, const std::nothrow_t&) noexcept {
    operator delete(p);
}

// May never return a null pointer.
void* operator new[](std::size_t size) {
    return operator new(size);
}

void operator delete[](void* p) noexcept {
    operator delete(p);
}

void* operator new[](std::size_t size, const std::nothrow_t& nt) noexcept {
    return operator new(size, nt);
}

void operator delete[](void* p, const std::nothrow_t& nt) noexcept {
    operator delete(p, nt);
}
于 2013-03-12T19:49:28.573 に答える
0

この関数を #pragma long_calls の下で定義するか、この関数内で long-call 属性を宣言できる場合、GCC に強制的にそれらを長い呼び出しにすることもできます。GCC オプションをチェックアウトします。

于 2014-11-28T04:22:15.407 に答える