I want to write "Hello World" without glibc, for this I need to write my little libc, I made some simple functions that do not require system calls, but now I want to make the write function so that the puts function works, but for write I need the syscall function, and In order to make syscall you need to know семmbrebre, but I don’t know him at all, I even ventured to try to write hello world, after a long googling and after several dozens of compilations, I saw "Hello World!" I got GG

__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;" // Системный вызов ядра ); } 

As far as I understand, for a system call, you need to write to a variable (or they are registries, I don’t know how the first differs from the second) r7 call number, and r1, r2, r3 ... variables passed to the variables, but how to write the syscall(номер вызова,Аргументы...) function syscall(номер вызова,Аргументы...) I don’t know, I’ll either have to write it completely in Assembler, which I’m definitely not able to, or I can write C and pass arguments to Assembler, I don’t know how either.

Can anyone help write the syscall function for the arm?

    2 answers 2

    Here, I syscall<N> quick “Hello World”, where the system calls are made using a number of syscall<N> functions, for a different number of arguments N You can, of course, be confused, and still make a single function with a variable number of arguments using va_list .

     #include <stdint.h> #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); } 

    Compile and run:

     $ gcc -nostdlib test.c -o test $ ./test Hello World 
    • What you need, and I wondered how to transfer variables from C to Assembler. Just why do you include stdint if it’s done with -nostdlib: D put in # define size_t unsigned int and everything worked as it should. - Vitaly Karpenko
    • size_t is a normal macro from stdint.h , it is processed by the preprocessor, -nostdlib does not affect this, and everything works if the header files themselves are available (I, of course, have, and I did not bother, wrote in haste ). And so, yes, if you want to completely get rid of the standard library, then you need to determine yourself. - Vadim Shender
    • The only thing that confuses me a little is that everything is converted to an int, is it not scary? - Vitaly Karpenko
    • @Vitaly, I don’t see a problem, all the system call parameters are put into general registers, so if only the int size was enough (if you have 64-bit architecture and 32-bit int , use long to put the addresses; well, or intptr_t from stdint.h , if not bother). - Vadim Shender

    An example from here for intel architects:

     # 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); } 

    compile:

     $ gcc -m32 -nostdlib -nostdinc -static hello.c -o hello 

    run:

     $ ./hello hello world 

    -

    architecture has another arm assembler.

    I can not check, because The arm is not at hand, so I give an example from here as it is:

     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" ); } 

    Compile, as I understand it, with the same parameters (well, except perhaps without specifying the bit -m32 - -m32 - which was not necessary in the first example).

    • What is it for? I do not need hello world on Assembler - Vitaly Karpenko
    • you need a system call in assembler. // but! seems to have understood. Do you need to show how assembly is inserted into a function in a C-file? - aleksandr barakin
    • I need a function that makes a system call like in glibc opennet.ru/man.shtml?topic=syscall&category=2&russian=2 - Vitaliy Karpenko
    • @Vitaly, I gave another example. - aleksandr barakin
    • Oh, this is what you need, only gcc swears at -m32 and "asm", replaced with __asm__ , but started writing something like this: error: impossible constraint in 'asm'__asm__ volatile ("int $0x80" : "=a" (ret) : "a" (syscall), "b" (arg1) : "memory"); - Vitaly Karpenko