Вопрос по assembly, x86, x86-64 – Требует ли printf дополнительное место в стеке на x86-64? [Дубликат]

3

This question already has an answer here:

Хотя я знаю, что лучше использовать встроенные функции компилятора, и в этом отношенииprintf_chk, а также положить данные в.rodata разделы, которые я изучаю, чтобы глубже понять язык ассемблера, и меня интересует компактный код. Есть что-то оprintf Я не понимаю. Я знаю, где поставить параметры, и я знаю, как использовать%al для varargs, но, похоже, требуется дополнительное пространство в стеке, которое я не могу учесть.

Эта короткая программа

        .text
        .globl  main
main:
        movsd   value(%rip), %xmm0    # value to print
        movl    $format, %edi         # format string
        movl    $1, %eax              # one floating-point arg
        call    printf
        movl    $0, %eax              # return 0 from main
        ret
        .align 8
value:  .double 74.321 
format: .asciz "%g\n"

дает segfault.

Однако, когда я добавляю дополнительное пространство стека к фрейму, он работает нормально:

        .text
        .globl  main
main:
        subq    $8, %rsp              # ADD SOME STACK SPACE TO FRAME (WHY?)
        movsd   value(%rip), %xmm0    # value to print
        movl    $format, %edi         # format string
        movl    $1, %eax              # one floating-point arg
        call    printf
        movl    $0, %eax              # return 0 from main
        addq    $8, %rsp              # REMOVE ADDED STACK SPACE
        ret
        .align 8
value:  .double 74.321 
format: .asciz "%g\n"

Может ли это быть проблема выравнивания? (Я получаю ту же проблему, когдаvalue а такжеformat находятся в.rodata раздел.)

stackoverflow.com/questions/8691792/… Ciro Santilli 新疆改造中心 六四事件 法轮功

Ваш Ответ

1   ответ
4

в соответствии с www.x86-64.org/documentation/abi.pdf, а также Microsoft.http://msdn.microsoft.com/en-us/library/ms235286(v=vs.80).aspx

Принято! Проверяется путем изменения значения с 8 на 16 и получения ошибки по умолчанию, затем смена на 24 и отсутствие ошибки по умолчанию. Интересно, что этоonly случается, когда я использую printf с векторными регистрами. Я не вижу никакого реального различия между моим первым примером, который работает нормальноwithout настройка RSP, и вторая, которая требует настройки. Что это за вторая версия, которая выводит стек из выравнивания, а первая - нет? Ray Toal
Ах, я помню сейчас: стек выравнивается по 16 байтов в начале функции main (). Инструкция вызова помещает 8-байтовый адрес возврата в стек, что приводит к его неправильному выравниванию и вызывает необходимость подстановки некоторого нечетного кратного 8 байтов для его выравнивания. Почему неправильно выровненный стек вызывает ошибку сегмента только тогда, когда используется векторный регистр (регистр! Не стек!), Мне не совсем понятно. Вероятно, недостаток понимания того, как работают varargs.
В x86-64 System V ABI (в Linux это выглядит как использование.rodata), rsp выровнен по 16 байтамbefore call, поэтому в начале нормальной функции, какmain, rsp-8 выровнен на 16, готов к другомуcall, Функции Variadic используют эту гарантию, когдаal>0 выгрузив xmm0..7 в стек с 16-ю выровненными хранилищами. (Так как__m128 Аргументы могут быть переданы в функции с переменными числами, и gcc не оптимизирует код своего кода для функций с переменными числами, которые никогда не заканчивают поиском регистра FP, аргумент которого шире, чем 8 байтов.)

Похожие вопросы