Syscall из встроенной сборки GCC

Можно ли написать один символ, используя syscall из встроенного блока сборки? если да, то как? он должен выглядеть "что-то" следующим образом:

__asm__ __volatile__
                    (
                     " movl $1,  %%edx \n\t"
                     " movl $80, %%ecx \n\t"
                     " movl $0,  %%ebx \n\t"
                     " movl $4,  %%eax \n\t"
                     " int $0x80       \n\t"
                     ::: "%eax", "%ebx", "%ecx", "%edx"
                    );

$80 является "P" в ascii, но ничего не возвращает.

любые предложения, которые были высоко оценены!

Ответ 1

Что-то вроде


char p = 'P';

int main()
{
__asm__ __volatile__
                    (
                     " movl $1,  %%edx \n\t"
                     " leal p , %%ecx \n\t"
                     " movl $0,  %%ebx \n\t"
                     " movl $4,  %%eax \n\t"
                     " int $0x80       \n\t"
                     ::: "%eax", "%ebx", "%ecx", "%edx"
                    );
}

Добавить: обратите внимание, что я использовал lea для загрузки эффективного адреса регистра char в ecx; для значения ebx я пробовал $0 и $1 и, похоже, все равно работает...

Избегайте использования внешнего char

int main()
{
__asm__ __volatile__
                    (
                     " movl $1,  %%edx \n\t"
                     " subl $4, %%esp \n\t"
                     " movl $80, (%%esp)\n\t"
                     " movl %%esp, %%ecx \n\t"
                     " movl $1,  %%ebx \n\t"
                     " movl $4,  %%eax \n\t"
                     " int $0x80       \n\t"
                     " addl $4, %%esp\n\t"
                     ::: "%eax", "%ebx", "%ecx", "%edx"
                    );
}

N.B.: это работает из-за эндемичности процессоров Intel!: D

Ответ 2

Вы можете использовать ограничения, специфичные для архитектуры, для непосредственного размещения аргументов в определенных регистрах, без инструкций movl в вашей встроенной сборке. Кроме того, затем вы можете использовать оператор & для получения адреса символа:

#include <sys/syscall.h>

void sys_putc(char c) {
    // write(int fd, const void *buf, size_t count); 
    int ret;
    asm volatile("int $0x80" : "=a"(ret): "a"(SYS_write), "b"(1), "c"(&c), "d"(1));
}

int main(void) {
    sys_putc('P');
    sys_putc('\n');
}

(В этом случае требуется =a(ret), чтобы указать, что сбрасываемые сейсмоприемники EAX.)

$ cc -m32 sys_putc.c && ./a.out
P

Вы также можете вернуть количество байтов, записанных в Syscall, и использовать "0" как ограничение, чтобы снова указать EAX:

int sys_putc(char c) {
    int ret;
    asm volatile("int $0x80" : "=a"(ret) : "0"(SYS_write), "b"(1), "c"(&c), "d"(1));
    return ret;
}

Ответ 3

IIRC, в вашем примере две вещи неверны. Во-первых, вы пишете stdin с mov $0,% ebx Во-вторых, запись берет указатель как второй аргумент, поэтому для записи одного символа вам нужен этот символ, хранящийся где-то в памяти, вы не можете записать значение непосредственно в% ecx

Пример:

.data
char: .byte 80
.text
mov $char, %ecx

Я только делал чистый asm в Linux, никогда не использовал inline с помощью gcc, вы не можете удалить данные в середине сборки, поэтому я не уверен, как вы получите указатель, используя встроенную сборку.

EDIT: Думаю, я просто вспомнил, как это сделать. вы можете нажать "p" на стек и использовать% esp

pushw $80
movl %%esp, %%ecx
... int $0x80 ...
addl $2, %%esp