Встроенный ассемблер на C. Неправильный перевод

У меня есть эта функция в C:

int write(int fd, char *buffer, int size)
{
    int ret;

    __asm__("mov $4, %%eax;"
            "mov %0, %%ebx;"
            "mov %1, %%ecx;"
            "mov %2, %%edx;"
            "int $0x80"
            : "=r"(ret)
            : "g"(fd), "g"(buffer), "g"(size)
            : "eax", "ebx", "ecx", "edx");

    if (ret < 0) {
        return -1;
    } else {
        return 0;
    }
}

Что переводится в этот код в ASM:

push   %ebp
mov    %esp,%ebp
push   %esi
push   %ebx
mov    $0x4,%eax
mov    %esi,%ebx
mov    0x8(%ebp),%ecx
mov    0xc(%ebp),%edx
int    $0x80
mov    %esi,%eax
sar    $0x1f,%eax
pop    %ebx
pop    %esi
pop    %ebp
ret

Поскольку fd, *buffer и size являются параметрами функции, они находятся в 0x8(%ebp), 0xc(%ebp) и 0x10(%ebp) соответственно. Почему GCC идентифицирует позицию fd в %esi, а две другие переменные смещены в стеке? Как я могу запустить эту функцию (правильно получить переменные в регистрах)?


person markmb    schedule 20.09.2014    source источник
comment
Почему бы вам не использовать write(2)? Он более переносим и может быть даже быстрее из-за vdso(7)   -  person Basile Starynkevitch    schedule 20.09.2014
comment
Как я комментирую ниже, я пишу свою собственную ОС как часть университетского предмета. Очевидно, что при использовании Linux я буду использовать запись.   -  person markmb    schedule 20.09.2014
comment
Обратите внимание, что подпрограммы int (прерывание) не имеют возвращаемого значения, поэтому эта последовательность кода не будет выполнена.   -  person user3629249    schedule 22.09.2014


Ответы (2)


Вероятно, это соглашение о вызовах в вашей архитектуре. Если вы хотите ограничить другие параметры регистрами, вы должны использовать ограничения регистров напрямую: например. "a" обозначает регистр eax.

Также $4 в начале мне кажется неправильным.

Что-то вдоль линии

     __asm__(
        "int $0x80"
        : "=b"(ret)
        : "c"(fd), "d"(buffer), "a"(size)
        );

следует делать, если это действительно те регистры, которые использует ваш системный вызов.

Но, в целом, я думаю, что вы не должны делать это самостоятельно. В вашей ОС определенно есть что-то вроде syscall, которое предоставляет вам эту функциональность.

person Jens Gustedt    schedule 20.09.2014
comment
Большое спасибо. Я неправильно понял концепцию ограничений. Они не там, где ожидается, а там, где я хочу, чтобы они были (если возможно, поместить это туда). Итак, теперь он работает так, как ожидалось. И в этом случае я не могу назвать ОС, потому что пишу ОС (университетская практика). - person markmb; 20.09.2014

Аргументы встроенного ассемблера нумеруются с нуля, начиная с выходных данных, поэтому %0 — это ret, %1 — fd, %2 — буфер и %3 — размер.

person Timothy Baldwin    schedule 25.09.2014