#c #linux #ассемблер #arm
Я хочу написать "Hello World" без glibc, для этого мне нужно написать свою маленькую libc, я сделал несколько простых функций которые не требуют системных вызовов, но теперь хочу сделать функцию write чтоб функция puts заработала, но для write нужна функция syscall, а для того чтоб сделать syscall нужно знать Асембрер, а я его совсем не знаю, я всеже рискнул попробовать написать hello world, после долгого гугления и через несколько десятков компиляций, я на экране увидел "Hello World!", в первые пол секунды я не поверил что у меня вышло Гг __asm__( ".data;" "msg:" ".ascii \"Hello, world!\n\";" // Строка для вывода "len = . - msg;" // Записуем в переменную len длину msg ); void _start() { __asm__( "mov r0, #1;" // Запись в поток #1 - stdout "ldr r1, =msg;" // Указатель на строку "ldr r2, =len;" // Длина строки "mov r7, #4;" // Номер системного вызова - 4 (write) "swi 0;" // Системный вызов ядра ); __asm__( "mov r0, #0;" // Возращаемое значение - 0 "mov r7, #1;" // Номер системного вызова - 1 (exit) "swi 0;" // Системный вызов ядра ); } Насколько я понял для системного вызова нужно записать в переменную(или это ригистры, я не знаю чем отличается первое от второго) r7 номер вызова, а в переменные r1, r2, r3... передаваемые аргументы, но как написать функцию syscall(номер вызова,Аргументы...) я не знаю, тут нужно либо полностью писать её на Ассемблере, а это я точно не смогу, либо писать на C и передавать аргументы в Ассемблер, это я тоже не умею. Может кто либо помочь написать функцию syscall для arm?
Ответы
Ответ 1
Вот, накидал по-быстрому "Hello World", где системные вызовы осуществляются с помощью ряда функций syscall, для различного количества аргументов N. Можно, конечно, заморочиться, и сделать еще единую функцию с переменным числом аргументов с помощью va_list. #include #define SYS_EXIT 1 #define SYS_WRITE 4 #define STDIN 0 #define STDOUT 1 #define STDERR 2 size_t strlen(const char *s) { size_t n; for (n = 0; *s; ++n, ++s) ; return n; } void syscall1(int cnum, int arg1) { __asm__ __volatile__( "mov r0, %0;" "mov r7, %1;" "swi 0;" : : "r"(arg1), "r"(cnum) : "r0", "r7" ); } void syscall3(int cnum, int arg1, int arg2, int arg3) { __asm__ __volatile__( "mov r0, %0;" "mov r1, %1;" "mov r2, %2;" "mov r7, %3;" "swi 0;" : : "r"(arg1), "r"(arg2), "r"(arg3), "r"(cnum) : "r0", "r1", "r2", "r7" ); } void _start() { char *msg = "Hello world\n"; syscall3(SYS_WRITE, STDOUT, (int)msg, strlen(msg)); syscall1(SYS_EXIT, 0); } Компиляция и запуск: $ gcc -nostdlib test.c -o test $ ./test Hello World Ответ 2
пример отсюда для intel-архитектуры: # hello.c static inline long syscall1(long syscall, long arg1) { long ret; asm volatile ("int $0x80" : "=a" (ret) : "a" (syscall), "b" (arg1) : "memory"); return ret; } static inline long syscall3(long syscall, long arg1, long arg2, long arg3) { long ret; asm volatile ("int $0x80" : "=a" (ret) : "a" (syscall), "b" (arg1), "c" (arg2), "d" (arg3) : "memory"); return ret; } int write(int fd, const void *buf, int count) { return syscall3(4, fd, (long)buf, count); } void exit(int status) { syscall1(1, status); } void _start() { int retval; retval = write(1, "hello world\n", 12); exit(0); } компилируем: $ gcc -m32 -nostdlib -nostdinc -static hello.c -o hello запускаем: $ ./hello hello world -- у архитектуры же arm другой ассемблер. проверить не могу, т.к. arm-а под рукой нет, поэтому привожу пример отсюда как есть: void _start() __attribute__ ((naked)); void _start() { main(); asm volatile( "mov r7, #1\n" /* exit */ "svc #0\n" ); } int main() { linuxc('X'); return 42; } void linuxc(int c) { asm volatile( "mov r0, #1\n" /* stdout */ "mov r1, %[buf]\n" /* write buffer */ "mov r2, #1\n" /* size */ "mov r7, #4\n" /* write syscall */ "svc #0\n" : /* output */ : [buf] "r" (&c) : "r0", "r1", "r2", "r7", "memory" ); } компилировать, как я понимаю, надо с теми же параметрами (ну, разве что без указания битности — -m32 — которая и в первом примере была необязательна).
Комментариев нет:
Отправить комментарий