How to make a syscall function?

Question:

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 a write function so that the puts function works, but write needs a syscall function, and for In order to make a syscall, you need to know Asembrer, but I don’t know him at all, I still ventured to try to write hello world, after a long googling and after several dozen compilations, I saw “Hello World!” On the screen, in the first half a second I did not believe that 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 are they registers, I don’t know how the first one differs from the second one) r7 is the call number, and the arguments passed to the variables r1, r2, r3 … but how to write the syscall(номер вызова,Аргументы...) I don’t know, here you need to either write it completely in Assembler, which I definitely won’t be able to, or write in C and pass arguments to Assembler, I don’t know how either.

Can anyone help write a syscall function for arm?

Answer:

Here, I threw in a quick "Hello World", where system calls are made using a number of syscall<N> functions, for a different number of arguments N . You can, of course, get confused and make another 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);
}

Compiling and running:

$ gcc -nostdlib test.c -o test
$ ./test
Hello World
Scroll to Top