c++ gcc powerpc

c++ - GCC se niega a emitir llamadas largas para el operador nuevo/eliminar en PowerPC



(2)

Las ramas de PowerPC solo tienen 24 bits disponibles para el desplazamiento de destino, por lo que si la sección de texto es demasiado grande, las ramas en un extremo no podrán alcanzar los objetivos en el otro. Hay una secuencia más larga de instrucciones que puede llegar a los objetivos más lejos (el desplazamiento es de 32 bits en lugar de 24), pero GCC no lo usa de forma predeterminada a menos que lo pase la opción -mlongcall . Sin embargo, incluso con esta opción activada, GCC aún genera llamadas cortas para ciertas funciones, a saber, operator new y operator delete

Por ejemplo, dado este código:

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

Una ejecución normal de GCC generará el ensamblaje:

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

Ejecutar GCC con la opción -mlongcall genera:

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

Las primeras cuatro instrucciones son una llamada larga a foo() , como se esperaba, pero la llamada al operator new ha cambiado. Las llamadas a las funciones aleatorias libc y libstdc ++ se convierten en llamadas largas como se espera. ¿Por qué el operator new y el operator delete llamadas todavía terminan como instrucciones? ¿Hay alguna forma de obligar a GCC a hacer llamadas largas también? Estoy usando GCC 4.7.2 en una máquina PowerPC Fedora de 64 bits (aunque estoy construyendo 32 bits)


Parece que la cadena de herramientas g ++ tiene algún tipo de error en la forma en que llama a las ocho funciones "reemplazables" de la biblioteca estándar de C ++ en su arquitectura, si esas funciones no son de hecho reemplazadas por el código de usuario.

Una implementación de reemplazo portátil para los ocho es:

#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); }


Si podemos definir esta función en #pragma long_calls o declarar el atributo de llamada larga dentro de esta función, también podemos forzar a GCC a hacer llamadas largas. Checkout GCC-opciones.