GCC拒绝在PowerPC上发出长期调用new/delete的操作

Mic*_*zek 16 c++ gcc powerpc

PowerPC分支只有24位可用于目标偏移,因此如果文本部分太大,则一端的分支将无法到达另一端的目标.有一个更长的指令序列可以到达更远的目标(偏移量是32位而不是24位),但GCC默认不使用它,除非你通过它-mlongcall选项.但是,即使启用此选项,GCC仍会为某些功能生成短调,即operator newoperator delete

例如,给定此代码:

extern void foo();

int main(int argc, char** argv) {
    foo();
    new char;
}
Run Code Online (Sandbox Code Playgroud)

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

bl _Z3foov // void foo()
bl _Znwj   // operator new(unsigned int)
Run Code Online (Sandbox Code Playgroud)

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

lis r9, _Z3foov@ha
addi r9, r9, _Z3foov@l
mtctr r9
bctrl
bl _Znwj
Run Code Online (Sandbox Code Playgroud)

foo()正如预期的那样,前四个指令是一个长期调用,但调用operator new没有改变.对随机libc和libstdc ++函数的调用都按预期转换为长调用.为什么operator newoperator delete电话仍然最终作为bl指示?有没有办法迫使海湾合作委员会长期打电话?我在64位PowerPC Fedora机器上使用GCC 4.7.2(虽然我正在构建32位)

asc*_*ler 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);
}
Run Code Online (Sandbox Code Playgroud)