Как System V amd64 обрабатывает очень длинные возвращаемые значения? - PullRequest
0 голосов
/ 03 января 2019

Я кратко изучаю ABI System V для архитектуры amd64 / x86-64, и мне любопытно, как он обрабатывает возвращаемые значения более 128 бит, где rax и rdx недостаточно.

Я написал следующий код C на 64-битной Ubuntu 18.04 (в более общем случае, на любой POSIX-совместимой системе amd64):

struct big {
    long long a, b, c, d;
};

struct big bigfunc(void) {
    struct big r = {12, 34, 56, 78};
    return r;
}

Скомпилировал его как gcc -S -masm=intel t.c и проверил t.s:

        .file   "t.c"
        .intel_syntax noprefix
        .text
        .globl  bigfunc
        .type   bigfunc, @function
bigfunc:
.LFB0:
        .cfi_startproc
        mov     QWORD PTR -40[rsp], rdi
        mov     QWORD PTR -32[rsp], 12
        mov     QWORD PTR -24[rsp], 34
        mov     QWORD PTR -16[rsp], 56
        mov     QWORD PTR -8[rsp], 78
        mov     rcx, QWORD PTR -40[rsp]
        mov     rax, QWORD PTR -32[rsp]
        mov     rdx, QWORD PTR -24[rsp]
        mov     QWORD PTR [rcx], rax
        mov     QWORD PTR 8[rcx], rdx
        mov     rax, QWORD PTR -16[rsp]
        mov     rdx, QWORD PTR -8[rsp]
        mov     QWORD PTR 16[rcx], rax
        mov     QWORD PTR 24[rcx], rdx
        mov     rax, QWORD PTR -40[rsp]
        ret
        .cfi_endproc
.LFE0:
        .size   bigfunc, .-bigfunc
        .ident  "GCC: (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0"
        .section        .note.GNU-stack,"",@progbits

Не удивительно, что определение структуры не компилируется ни в какие инструкции, поэтому вывод содержит только функцию bigfunc. Выходная сборка выглядит довольно просто, выделяя память из стека для struct big r, назначая начальные значения и возвращая ее.

Если я правильно понимаю, перед выполнением ret регистр rax содержит значение rdi в начале вызова функции (с QWORD PTR -40[rbp]). Согласно SysV, rdi является первым аргументом, предоставленным функции, что невозможно, потому что функция не принимает аргументов. Итак, у меня есть несколько вопросов здесь:

  1. Что такое rdi, когда функция bigfunc не принимает аргументов?
  2. Что такое rax (как регистр, содержащий возвращаемое значение), когда rdx не затрагивается в этой функции?
  3. Как функция возвращает эту 256-битную структуру C?

1 Ответ

0 голосов
/ 03 января 2019

Согласно ABI (1), стр. 22 * ​​1003 *

Если тип имеет класс MEMORY, тогда вызывающая сторона предоставляет пространство для возвращаемого значения и передает адрес этогохранение в% rdi, как если бы это был первый аргумент функции.По сути, этот адрес становится «скрытым» первым аргументом.Это хранилище не должно перекрывать любые данные, видимые вызываемому абоненту через другие имена, кроме этого аргумента.По возвращении% rax будет содержать адрес, который был передан вызывающим абонентом в% rdi

. Страницы 17, 18 и 19 описывают классификации. Я верю, что на странице 19 приведено следующее:struct big как класс MEMORY.

(c) Если размер агрегата превышает два восьмибайта, а первый восьмибайтовый не SSE или любой другой восьмибайтовый не SSEUP, весьаргумент передается в память.

т.е. вызывающий должен выделить память для возвращаемого значения и передать указатель на эту память в% rdi (и вызываемая функция возвращает тот же адрес в% rax)

(1) есть новые официальные версии ABI на https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI, хотя ссылки в настоящее время не работают должным образом.

...