NASM printf print 64-битный двойной сегмент - PullRequest
2 голосов
/ 23 февраля 2020

Я пытаюсь заставить себя печатать дубликаты в сборке, но у меня ничего не получается. Я получаю segfault при вызове своей собственной функции, которую я планирую использовать в качестве помощника для печати двойников в целях отладки. Я следовал этим printf примерам: https://www.csee.umbc.edu/portal/help/nasm/sample.shtml

Мой код в настоящее время выглядит так:

section .data
    formatStrf: db `The number is %f\n`,0

section .text

extern printf

printfcallfloat:

    ;Pass in RDI
    PUSH RDI ;Preserve value of rdi
    PUSH RAX ;Preserve value of RAX

    PUSH RDI;The value we want to print
    PUSH DWORD formatStrf
    CALL printf ;Segfault

    POP RAX;Pop the stack back (too lazy to manually change the RSP value)
    POP RAX

    POP RAX;Restore the RAX and RDI
    POP RDI
    RET

Я передаю значение с плавающей запятой в RDI reg следующим образом:

MOVSD QWORD [RSP], XMM0 ;Copy to stack
MOV RDI, QWORD [RSP]
CALL printfcallfloat

РЕДАКТИРОВАТЬ: я запускаю это на linux.

Ответы [ 2 ]

4 голосов
/ 24 февраля 2020

В x86_64 аргументы передаются в регистрах, а не в стеке (стек используется только в том случае, если размер аргументов слишком велик, чтобы поместиться в регистрах). Все подробности 1 выложены в SYSV ABI для x86_64

Основой этого является то, что первые 6 аргументов целого числа / указателя передаются в RDI / RSI / RDX / RCX / R8 / R9, в то время как первые 8 аргументов с плавающей запятой / двойной передачей передаются в XMM0..XMM7. Кроме того, вам необходимо указать число регистров XMM, используемых для аргументов в AL 2 . Итак, в вашем случае вам нужен формат в RDI, двойное значение в XMM0 и 1 в AL

На странице википедии также есть много хорошей (краткой) информации об этом.


1 Для систем, не принадлежащих Microsoft - MS, являясь MS, делают что-то несовместимым образом

2 На самом деле вам нужно установить это только для функций varargs, которые используют хотя бы один регистр XMM. Для функций без varargs это будет игнорироваться, и если оно будет установлено слишком большим для функции varargs, результатом будет несколько потерянных циклов (сохранение ненужных регистров XMM), но на самом деле ничего не сломается.

0 голосов
/ 24 февраля 2020

Редактировать : как указано в комментариях, это только для Windows архитектур. См. Ответ Криса для соглашения о Linux системах.


На странице, на которую вы ссылаетесь, есть примеры для x86, 32-битной архитектуры. Архитектура x86_64 отличается тем, как аргументы передаются в функции.

Первые четыре целочисленных аргумента передаются в регистрах. Целочисленные значения передаются в порядке слева направо в RCX, RDX, R8 и R9 соответственно. Аргументы пять и выше передаются в стек.

source

Любые аргументы с плавающей точкой обычно передаются вместо XMM0...3, но для varargs это отличается:

Если параметры передаются через переменные (например, аргументы с многоточием), то применяется обычное соглашение о передаче параметров регистра, в том числе пятый и последующие аргументы в стек. Ответственность вызываемого абонента состоит в том, чтобы сбросить аргументы, для которых взят их адрес. Только для значений с плавающей запятой, как целочисленный регистр, так и регистр с плавающей запятой должны содержать значение, если вызываемый объект ожидает значение в целочисленных регистрах.

Так, другими словами, перед чтобы позвонить на printf, вы должны установить RCX на строку формата и установить RDX и XMM1 на номер.

...