16

PowerPC 分支只有 24 位可用于目标偏移量,因此如果文本部分变得太大,一端的分支将无法到达另一端的目标。有更长的指令序列可以到达更远的目标(偏移量是 32 位而不是 24 位),但 GCC 默认不使用它,除非您将-mlongcall选项传递给它。operator new然而,即使打开了这个选项,GCC 仍然会为某些函数生成短调用,即operator delete

例如,给定以下代码:

extern void foo();

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

GCC 的正常运行将生成程序集:

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

-mlongcall使用该选项运行 GCC 会生成:

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

正如预期的那样,前四个指令是对 的长时间调用foo(),但对 的调用operator new没有改变。对随机 libc 和 libstdc++ 函数的调用都按预期转换为长调用。为什么operator newoperator delete调用仍然作为bl指令结束?有什么办法可以迫使 GCC 也进行长时间的通话吗?我在 64 位 PowerPC Fedora 机器上使用 GCC 4.7.2(虽然我正在构建 32 位)

4

2 回答 2

3

似乎 g++ 工具链在调用架构上 C++ 标准库的八个“可替换”函数时存在某种错误,如果这些函数实际上没有被用户代码替换的话。

所有八个的可移植替代实现是:

#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 回答