Некорректное красное зонирование стека при генерации кода x86-64

Это вывод компилятора из функции ядра Linux (скомпилированный с -mno-red-zone):

load_balance:
.LFB2408:
        .loc 2 6487 0
        .cfi_startproc
.LVL1355:
        pushq   %rbp    #
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp      #,
        .cfi_def_cfa_register 6
        pushq   %r15    #
        pushq   %r14    #
        pushq   %r13    #
        pushq   %r12    #
        .cfi_offset 15, -24
        .cfi_offset 14, -32
        .cfi_offset 13, -40
        .cfi_offset 12, -48
        movq    %rdx, %r12      # sd, sd
        pushq   %rbx    #
.LBB2877:
        .loc 2 6493 0
        movq    $load_balance_mask, -136(%rbp)  #, %sfp
.LBE2877:
        .loc 2 6487 0
        subq    $184, %rsp      #,
        .cfi_offset 3, -56
        .loc 2 6489 0
     ....

Обратите внимание на "subq $184, %rsp" после того, как компилятор уже пролил на стек (разлив безумный, кстати, так как он проливает постоянное значение!)

Линус сообщил об этой ошибке в gcc 2 дня назад. Но я не понимаю, в чем ошибка. Это почему subq неправильно?

Изменить: отчет об ошибке здесь: извините за то, что не включил это раньше https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61904

2 ответа

Решение

Я не понимаю, почему это subq неправильно?

Проблема в том, что его порядок относительно movq $load_balance_mask, -136(%rbp) инструкция. subq выделяет пространство в стеке, изменяя указатель стека, и movq пишет в местоположение в пределах этой выделенной области. Но в этом случае movq предшествует subqто есть он записывает (пока что) нераспределенное пространство стека. А что если прерывание происходит между movq и subq и обработчик прерываний пытается коснуться той же области стека? В результате могут произойти все виды странных вещей, большинство из которых, вероятно, будут плохими.

Имея movq Сначала было бы хорошо при наличии красной зоны. Цитата из Википедии:

Красная зона - это область фиксированного размера в памяти за указателем стека, которая не была "выделена". Эта область памяти не должна изменяться обработчиками прерываний / исключений / сигналов. Это позволяет использовать пространство для временных данных без дополнительных затрат на изменение указателя стека. ABI x86-64 требует 128-байтовой красной зоны.

Однако, как писал Линус в ветке электронной почты об этой ошибке: "Но мы строим ядро ​​с -mno-red-zone. Мы * не * следуем ABI x86-64 по поводу redzoning".
И с отключенными красными зонами генератору кода не должно быть разрешено выводить movq перед subq,

Я не вижу там проблемы. Константа на самом деле не разливается, она инициализирует локальную переменную. Красная зона - 128 байт под указателем стека, поэтому -136(%rbp) в пределах, потому что rbp имеет значение rsp до пяти нажатий уменьшил его на 40. Компилятору разрешено настраивать rsp всякий раз, когда хочется. Это может быть alloca вызов тоже.

Вы могли предоставить ссылку или хотя бы краткое изложение отчета об ошибке. Я не смог найти что-нибудь подходящее в gcc bugzilla. Оригинальный C источник также был бы полезен.

Другие вопросы по тегам