Регистр XMM1 сборки x86-64 теряет свое значение - PullRequest
2 голосов
/ 24 февраля 2020

Итак, я работаю над этим фрагментом кода сборки и столкнулся со странной проблемой: регистр XMM1, похоже, теряет свое значение в середине выполнения, хотя я не думаю, что здесь используются какие-либо инструкции это может изменить его ценность. Ниже приведен проблемный c фрагмент кода.

    MOVSD QWORD [RSP], XMM1 ;Copy to stack
    MOV RDI, QWORD [RSP]
    CALL printfcallfloat;Prints floating point value from the RDI register, preserves all registers

    ;Load 10 to the fpu stack
    PUSH 10
    FILD QWORD [RSP]
    POP RDI

    MOVSD QWORD [RSP], XMM0 ;Copy to stack
    FLD QWORD [RSP];Load number float from XMM0 to the x87

    ;Do the math y = xmm0 (2), x=10 X*LOG2(Y)
    FYL2X

    ;We now have the result of x*log2(y) in ST(0)
    FSTP QWORD [RSP];Pop the result from the logarithm to the stack
    MOVSD XMM0, QWORD [RSP];Move the result back to xmm0

    ;print XMM0 and XMM1
    MOVSD QWORD [RSP], XMM0 ;Copy to stack
    MOV RDI, QWORD [RSP]
    CALL printfcallfloat;This preserves all registers

    MOVSD QWORD [RSP], XMM1 ;Copy to stack
    MOV RDI, QWORD [RSP]
    CALL printfcallfloat;This preserves all registers

Это дает следующий вывод:

10.000000
10.000000
-nan

Я очень смущен тем, что здесь происходит.

РЕДАКТИРОВАТЬ: реализация функции печати выглядит следующим образом:

printfcallfloat:

    ;Value is passed here in RDI
    PUSH RDI ;Preserve value of rdi
    PUSH RAX ;Preserve value of RAX
    pushxmm XMM0 ;Preserve XMM0
    ;Double is passed to printf in XMM0
    ;Now we move the value from the reg to the XMM0 using stack
    PUSH RDI
    popxmm XMM0
    MOV AL, 1;We are passing one argument so al should be 1
    MOV RDI, formatStrf ;Format string is passed in RDI
    CALL printf

    ;Restore XMM0
    popxmm XMM0
    POP RAX
    POP RDI
    RET

1 Ответ

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

Хорошо, так что это была проблема смещения стека, и метод printf действительно перезаписал значение в XMM1. Я не принял во внимание возвращаемое значение, помещаемое в стек вызываемым объектом моего кода сборки (что приводит к смещению стека), и поэтому я начал получать ошибки segfault после добавления нажатия и выталкивания в регистре XMM1. Просто добавили SUB RSP, 8 в начало моего кода, чтобы выровнять стек по 16 байтов, что является де-факто стандартом, который кажется, и это также достаточно большое выравнивание для регистров SSE, которые я также использую в коде. Я сделал следующие изменения (в комментариях в коде). Подпрограмма печати:

printfcallfloat:

    ;Value is passed here in RDI
    PUSH RDI ;Preserve value of rdi
    PUSH RAX ;Preserve value of RAX
    pushxmm XMM0
    pushxmm XMM1 ;Added this to make sure XMM1 is surely preserved after call

    PUSH RDI
    popxmm XMM0
    MOV AL, 1;We are passing one argument so al should be 1
    MOV RDI, formatStrf ;Format string is passed in RDI

    CALL printf ;Does not necessarily preserve SSE registers

    ;Restore XMM anmd other regs
    popxmm XMM1 ;Pop the XMM1 reg also
    popxmm XMM0
    POP RAX
    POP RDI
    RET

В основной код просто добавили следующее, чтобы выровнять стек после ввода, хотя я не уверен, что это правильный метод, дайте мне знать, если я делаю это неправильно :

    ;Align the stack
    SUB RSP, 8 ;8 bytes return address
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...