PowerPC分支只有24位可用于目标偏移,因此如果文本部分太大,则一端的分支将无法到达另一端的目标。有一个更长的指令序列可以到达更远的目标(偏移量是32位而不是24位),但GCC默认不使用它,除非你传递-mlongcall
选项。但是,即使启用此选项,GCC仍会为某些功能生成短暂呼叫,即operator new
和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 new
和operator delete
来电仍以bl
指令结尾?有没有办法迫使海湾合作委员会长期打电话?我在64位PowerPC Fedora机器上使用GCC 4.7.2(虽然我正在构建32位)
答案 0 :(得分: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);
}
答案 1 :(得分:0)
如果我们可以在#pragma long_calls下定义这个函数或者在这个函数中声明long-call属性,我们也可以强制GCC对它们进行长调用。 结帐GCC选项。