GCC отказывается выдавать длинные вызовы для оператора new / delete на PowerPC

ветви PowerPC имеют только 24 бита, доступных для целевого смещения, поэтому, если текстовый раздел становится слишком большим, ветви на одном конце не смогут достичь целей на другом. Существует более длинная последовательность инструкций ,которые могут достигать целей дальше (смещение составляет 32 бита вместо 24), но GCC не использует его по умолчанию, если вы не передадите его . Однако даже с этой опцией 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)

запуск 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 инструкции? Есть ли способ заставить GCC делать длинные звонки? Я использую GCC 4.7.2 на 64-битной машине PowerPC Fedora (хотя я создаю 32-бит)

2 ответов


похоже, что G++ toolchain имеет какую-то ошибку в том, как он вызывает восемь "сменных" функций стандартной библиотеки 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);
}

Если мы можем определить эту функцию в #pragma long_calls или объявить атрибут long-call внутри этой функции, мы можем заставить GCC также совершать их длинные вызовы. Оформить заказ GCC-опции.