Вградено асемблиране в 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, ще използвам write.   -  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 използва.

Но като цяло мисля, че не трябва да правите това сами. Вашата ОС със сигурност има нещо като 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