Как получить доступ к первому параметру вызова scanf в сборке? - PullRequest
0 голосов
/ 01 ноября 2019

Скажем, у меня есть следующий код, написанный в (AT & T) Assembly:

push qword 0
push qword 0
mov rax, 2                ;Tell rax we receive 2 floats
mov rdi, floatformat      ;floatformat db "%lf %lf",0

mov rsi, rsp              ;I am assuming my logic flaw is in these two lines
mov rdx, rsp

call scanf
pop rax                   ;Clean up the stack
pop rax

movsd xmm0, [rsi]         ;This does not give the value I want

Как указано в комментариях выше, я хочу, чтобы xmm0 содержал первый float, который вводит пользователь, когда call scanfвыполняется, но только получить второй поплавок. Я знаю, что это, скорее всего, связано с операцией mov rdx, rsp, но если она не выполняется, моя программа не работает правильно для чтения пользовательских входных данных.

Как я могу получить первый плавающийпользователь вводит в? Я пытался исследовать scanf соглашения о вызовах, но пока не нашел четкого ответа.

1 Ответ

2 голосов
/ 01 ноября 2019

%lf - это double, а не единичная точность float. И нет, 2 аргумента, которые вы передаете scanf: double *, , а не double, поэтому вы должны установить AL=0 не 2.

В любом случае, ваша проблемаявляется то, что вы передали один и тот же указатель для обоих выходных операндов. И это scanf уничтожает свои регистры передачи аргументов, как это позволяет соглашение о вызовах. ( Какие регистры сохраняются посредством вызова функции linux x86-64 )

Эквивалент C похож на scanf("%lf %lf", &b, &b) после резервирования стекового пространства для double a,b;

    ; assuming stack is 16-byte aligned to start with,
    ; e.g. if your function started with an odd number of pushes

    sub   rsp, 16
    mov   rsi, rsp        ; pointer to low slot
    lea   rdx, [rsp+8]    ; pointer to high slot
    lea   rdi, [rel format_string]    ; use RIP-relative LEA for 64-bit static addresses
    xor   eax,eax         ; 0 FP args in regs to a variadic function
    call  scanf           ; scanf(fmt, &tmp0, &tmp1)

    movaps xmm0, [rsp]     ; load both doubles
    add    rsp, 16         ; now tmp0 and tmp1 are below RSP, in the red-zone

    movsd   xmm1, [rsp-8]  ; or shuffle xmm0 to get tmp1 from the high half.

фиктивный push / pop обычно стоит только (вместо add rsp, imm8) для one слот стека, и в основном, если вы собираетесь сразу же call вместо явной ссылки на RSP. После этого будет выполнена синхронизация стека.

...