Есть ли жизнь за пределами libc.so или как писать на голом С

Модератор: Модераторы разделов

Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение sabir »

Итак, есть ли жизнь за пределами libc.so?
Определенно есть, более того, только там она и существует в реальности.
Собственно вопрос можно сформулировать как, можно ли писать на "голом цэ", но без либцэ и как следствие вообще без каких-либо зависимостей?
Как оказалось в этом нет почти ничего сложного.
Проблема в том, что вменяемого множества букв на тему встроенного асма в гугле я не нашел, с примерами таже ситуация, мне было интересно, как вызвать syscall, ежели число аргументов больше 3-х, а именно:
нулевой аргумент = "a" = RAX = номер syscall
первый аргумент = "D" = RDI
второй аргумент = "S" = RSI
третий аргумент = "d" = RDX
а вот дальше следует "c", что как не сложно догадаться означает RCX, а еще дальше R8, R9, так ведь?
А вот и нет, разрабы гцц забили болт на R8 - R15 регистры, и что удивительно на RCX тоже, ниже приведен один из вероятных примеров кода, как можно забить болт на разрабов гцц, может кому на что и сгодиться:

Код: Выделить всё

// x86_64 Linux only
// компилить, как вариант, можно так:
// cc -Wall -s -nostdlib -march=native -pipe -O2 -Os -mfpmath=sse -std=c99 -o main main.c

#include <sys/types.h>
#include <sys/mman.h>

#define sys_write            1
#define sys_close            3
#define sys_mmap            9
#define sys_munmap            11
#define sys_exit            60
#define sys_create            85

#define MAP_ANONYMOUS        0x20

void exit(int code)
{
    __asm__ __volatile__(
        "syscall"
        :
        : "a"(sys_exit), "D"(code)
        : "cc", "rcx", "r11", "memory");
    __builtin_unreachable(); // syscall above never returns
}

ssize_t write(int fd, const void * buf, size_t size)
{
    ssize_t result;
    __asm__ __volatile__(
        "syscall"
        : "=a"(result)
        : "a"(sys_write), "D"(fd), "S"(buf), "d"(size)
        : "cc", "rcx", "r11", "memory");
    return result;
}

void * mmap(void * addr, size_t len, int prot, int flags, int fd, off_t offset)
{
    void * p = 0;

    register int r8 __asm__ ("r8") = fd;
    register off_t r9 __asm__ ("r9") = offset;
    register int r10 __asm__ ("r10") = flags;

    __asm__ __volatile__(
        "syscall"
        : "=a"(p)
        : "a"(sys_mmap), "D"(addr), "S"(len), "d"(prot), "r"(r10), "r"(r8), "r"(r9)
        : "cc", "rcx", "r11", "memory");
    return p;
}

int munmap(void * addr, size_t len)
{
    int result;
    __asm__ __volatile__(
        "syscall"
        : "=a"(result)
        : "a"(sys_munmap), "D"(addr), "S"(len)
        : "cc", "rcx", "r11", "memory");
    return result;
}

int creat(const char * pathname, mode_t mode)
{
    int result;
    __asm__ __volatile__(
        "syscall"
        : "=a"(result)
        : "a"(sys_create), "D"(pathname), "S"(mode)
        : "cc", "rcx", "r11", "memory");
    return result;
}

int close(int fd)
{
    int result;
    __asm__ __volatile__(
        "syscall"
        : "=a"(result)
        : "a"(sys_close), "D"(fd)
        : "cc", "rcx", "r11", "memory");
    return result;
}

void _start()
{
    int fd = creat("/tmp/test.txt", 0600);

    int * map = mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if(map == MAP_FAILED)
    {
        write(1, "mmap failed\n", 12);
        exit(-1);
    }

    write(fd, "The truth is you don't need libc", 32);
    munmap(map, 4096);
    close(fd);

    map = mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if(map == MAP_FAILED)
    {
        write(1, "mmap failed\n", 12);
        exit(-1);
    }

    map[49] = 0xff000000;
    munmap(map, 4096);

    write(1, "Success\n", 8);
    exit(0);
}

На "правильность" не претендую, написано в рамках "just for fun"
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu
Контактная информация:

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение serzh-z »

О чем это всё и причем тут разрабы GCC?

В наборе инструкций x86-64 есть выделенная инструкция syscall, которая использует регистры rax, rdi, rsi, rdx, r10, r8, r9 для номера вызова и аргументов, и rax - для возвращаемого значения. rcx и r11 затираются, остальные сохраняются.

Так же в Linux (да и во многих других ядрах ОС, наверное), как понимаю, до сих пор поддерживается старый распространенный подход для реализации интерфейса системных вызовов через прерывание 0x80 с использованием 32-битных регистров eax-ebp.
Спасибо сказали:
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение sabir »

serzh-z писал(а):
18.04.2016 13:23
О чем это всё

Как написано выше, это все о том, как писать программы на С без libc, другой вопрос зачем и кому это надо. Это надо мне и всем тем, для кого такая возможность предусмотрена разрабами.
Если я не правильно написал код, скажите как должно быть, конкретно где ошибка(и)?
serzh-z писал(а):
18.04.2016 13:23
и причем тут разрабы GCC?

Вполне допускаю, что это не разрабы GCC, значит это разрабы GAS.
System V AMD64 ABI
The first six integer or pointer arguments are passed in registers RDI, RSI, RDX, RCX (R10 in the Linux kernel interface), R8, and R9, while XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 and XMM7 are used for certain floating point arguments.

RCX, как минимум, учавствует в передаче аргументов и можно было бы это учесть, как в случае с i386, а именно:
четвертый аргумент = "с" = RСX
если в Linux вместо RCX надо юзать R10, ну и хорошо, значит можно например так:
четвертый аргумент = "с" = R10
кроме того, никто бы не умер, если бы для R8 и R9 также былы бы предусмотрены свои собственные "обозначения"
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение NickLion »

sabir
А при чём конвенция вызова обычных функций и syscall? В мануале сказано:
(Intel® 64 and IA-32 Architectures Software Developer's Manual Volumes 2A @ 2B, and 2C; Chapter 4; 4.2; SYSCALL) писал(а):[quote="(Intel® 64 and IA-32 Architectures Software Developer's Manual
Volumes 2A @ 2B, and 2C; Chapter 4; 4.2; SYSCALL)"]SYSCALL saves the RIP of the instruction following SYSCALL to RCX and loads a new
RIP from the IA32_LSTAR (64-bit mode). Upon return, SYSRET copies the value
saved in RCX to the RIP.
SYSCALL saves RFLAGS (lower 32 bit only) in R11. It then masks RFLAGS with an
OS-defined value using the IA32_FMASK (MSR C000_0084). The actual mask value
used by the OS is the complement of the value written to the IA32_FMASK MSR.
None of the bits in RFLAGS are automatically cleared (except for RF). SYSRET
restores RFLAGS from R11 (the lower 32 bits only).

Т.е. значение в RCX и R11 будет перезаписано и использовать их для передачи в системный вызов нельзя.
Спасибо сказали:
yoshakar
Сообщения: 259
ОС: Debian Stretch

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение yoshakar »

По-моему, если используется ассемблер — это уже не "голый C". В любом случае, если всё что нужно — это "жить за пределами libc", то необходимость использовать ассемблер и разбираться с (и завязываться на) ABI неясна.
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu
Контактная информация:

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение serzh-z »

sabir писал(а):
18.04.2016 22:38
Вполне допускаю, что это не разрабы GCC, значит это разрабы GAS.

sabir писал(а):
18.04.2016 22:38
Как написано выше, это все о том, как писать программы на С без libc,
Причем тут вообще GAS... Это соглашение по syscall/sysret от Intel и AMD. Если не устраивает "голый" syscall и нет возможно скопипастить готовую обертку вокруг syscall из libc/bionic/ulibc и т.д., то можно, вместо использования ассемблерных вставок (и рекомендуется), вызывать ядерный API через vDSO: https://github.com/torvalds/linux/tree/mast...umentation/vDSO
Спасибо сказали:
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение sabir »

NickLion писал(а):
19.04.2016 00:22
sabir
А при чём конвенция вызова обычных функций и syscall?

Т.е. syscall можно вызвать забив болт на ABI или я чего то не понимаю?

Допускаю, что я не достаточно четко сформировал свою позицию, а она такая:
1. есть разные компиляторы, среди которых не последнее место занимает GCC
2. В GCC есть встроенный ассемблер, у которого, в свою очередь, предусмотрены т.н. "commonly used constraints"
+---+--------------------+
| r | Register(s) |
+---+--------------------+
| a | %eax, %ax, %al |
| b | %ebx, %bx, %bl |
| c | %ecx, %cx, %cl |
| d | %edx, %dx, %dl |
| S | %esi, %si |
| D | %edi, %di |
+---+--------------------+
3. Я, как обычный юзер GCC, желаю использовать предоставленную разрабами GCC возможность ассемблерной вставки, например мне нужно вызвать syscall sys_mmap
4. У sys_mmap 6 аргументов: void * mmap(void * addr, size_t length, int prot, int flags, int fd, off_t offset);
5. Для вызова sys_mmap я должен передать 6 аргументов через регистры RDI, RSI, RDX, R10, R8, R9, например:

xor r9, r9
xor r8, r8
dec r8
mov r10, MAP_PRIVATE | MAP_ANONYMOUS
mov rdx, PROT_READ | PROT_WRITE
mov rsi, 4096
xor rdi, rdi
mov rax, sys_mmap
syscall

6. Для первых трех регистров RDI, RSI, RDX разрабами GCC предусмотрены "constraints", а именно:
+---+--------------------+
| r | Register(s) |
+---+--------------------+
| d | %edx, %dx, %dl |
| S | %esi, %si |
| D | %edi, %di |
+---+--------------------+
а вот для R10, R8, R9 "constraints" разрабами GCC НЕ предусмотрены, т.е. говоря рабоче-крестьянским языком, разрабы GCC забили болт на регистры R10, R8, R9, именно это я и написал в самом первом сообщении.
Далее участник форума с ником "serzh-z" выразил своё не согласие с моей позицией, с его точки зрения разрабы GCC здесь не причем. Тогда у меня возникает вопрос, к более опытным и технически продвинутым участникам форума, который можно сформулировать как:
А кто тогда причем, кто тот человек или группа лиц, который(ая) решает, что для RDI, RSI, RDX "constraints" нужны, а для R10, R8, R9 "constraints" не нужны и по какой причине? Я собственно об этом.
yoshakar писал(а):
19.04.2016 01:15
По-моему, если используется ассемблер — это уже не "голый C". В любом случае, если всё что нужно — это "жить за пределами libc", то необходимость использовать ассемблер и разбираться с (и завязываться на) ABI неясна.

А разве можно вызвать syscall без ассемблера, я гуглил по этому вопросу, но ничего не нашел, если Вам не сложно, запостите простой пример вызова sys_mmap, например, на любом ЯВУ, без ассемблера и без каких-либо библиотек, мне бы пригодилось

serzh-z
Кто отвечает за "constraints" во встроенном ассемблере, с моей точки зрения это разрабы GCC, а с Вашей?
Кроме того Вы так и не ответили на мой вопрос:
sabir писал(а):
18.04.2016 22:38
Если я не правильно написал код, скажите как должно быть, конкретно где ошибка(и)?
Спасибо сказали:
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение sabir »

serzh-z писал(а):
19.04.2016 16:16
то можно, вместо использования ассемблерных вставок (и рекомендуется), вызывать ядерный API через vDSO: https://github.com/torvalds/linux/tree/mast...umentation/vDSO

Я посмотрел Вашу ссылку и обнаружил следующее:
в файле vdso_standalone_test_x86.c, если я правильно понял, реализован вызов syscall с тремя аргументами, строки 40 - 54:

Код: Выделить всё

static inline long x86_syscall3(long nr, long a0, long a1, long a2)
{
    long ret;
#ifdef __x86_64__
    asm volatile ("syscall" : "=a" (ret) : "a" (nr),
              "D" (a0), "S" (a1), "d" (a2) :
              "cc", "memory", "rcx",
              "r8", "r9", "r10", "r11" );
#else
    asm volatile ("int $0x80" : "=a" (ret) : "a" (nr),
              "b" (a0), "c" (a1), "d" (a2) :
              "cc", "memory" );
#endif
    return ret;
}

В этом фрагменте я вижу использование встроенного ассемблера для вызова syscall'ов с тремя аргументами, где 'long nr' это номер syscall, 'long a0' это первый аргумент, 'long a1' это второй аргумент, 'long a3' это третий аргумент.
Что такое vDSO я не знаю и мне не стыдно в этом признаться, однако с Ваших слов <вместо использования ассемблерных вставок (и рекомендуется), вызывать ядерный API через vDSO> использовать ассемблерные вставки не желательно, однако, опять же если я правильно понял, Andy Lutomirski именно это и делает, т.е. использует ассемблерную вставку, разве нет?
Наше с Вами разногласие заключается в том, что в гуглах много примеров использования встроенного ассемблера для вызова syscall с 1 - 3 аргументами, пример из Вашей ссылки <"D" (a0), "S" (a1), "d" (a2)>, первый аргумент помещается в RDI = "D", второй в RSI = "S" и третий соответственно в RDX = "d", Вы с этим согласны?
А меня, просто по приколу, т.к. я пишу на настоящем ассемблере, заинтересовал вопрос:
Ну а ежели, к примеру, я желаю вызвать syscall с более чем тремя аргументами, например sys_mmap, какие конкретно "букафки" я должен написать во вставку для 4 - 6 аргументов, после долгих поисков в гугле нашел на форуме "stackoverflow" ответ, что зарезервированных букв для RCX(R10), R8, R9 нет, но можно сделать через ..., о чем собственно мой первый пост и говорит.
Далее я ткнул пальцем в небо и предположил, что за "букафки", которые по-пиндосски называются "constraints" отвечают разрабы GCC, если это не так, спорить не буду, т.к. мне пох, поверю Вам на слово, скажите кто ответственен за "constraints" во встроенный в GCC ассемблер, если не разрабы GCC, то кто?
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение NickLion »

sabir писал(а):
19.04.2016 16:52
Т.е. syscall можно вызвать забив болт на ABI или я чего то не понимаю?

ABI бывает разный. Это просто описание интерфейса. Есть ABI для обычных вызовов, есть для системных.
SYSCALL имеет свою конвенцию вызова, которая ограничивается реализацией этой инструкции производителями процессора (цитату я привёл) и реализацией ядра ОС для данного процессора, на которой происходит действие.
Просто сначала почитайте о разнице между обычными вызовами и системными.
Спасибо сказали:
yoshakar
Сообщения: 259
ОС: Debian Stretch

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение yoshakar »

sabir писал(а):
19.04.2016 16:52
А разве можно вызвать syscall без ассемблера, я гуглил по этому вопросу, но ничего не нашел, если Вам не сложно, запостите простой пример вызова sys_mmap, например, на любом ЯВУ, без ассемблера и без каких-либо библиотек, мне бы пригодилось
Можно. Самый простой способ — прилинковать libc статически.
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu
Контактная информация:

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение serzh-z »

sabir писал(а):
19.04.2016 18:03
А меня, просто по приколу, т.к. я пишу на настоящем ассемблере, заинтересовал вопрос:
Мне тоже так показалось, поэтому и не понял какое отношение имеют какие-то там соглашения и пожелания от разрабочиков компиляторов к набору инструкций.

sabir писал(а):
19.04.2016 18:03
скажите кто ответственен за "constraints" во встроенный в GCC ассемблер, если не разрабы GCC, то кто?
Может быть разработчик конкретного процессора? =)

sabir писал(а):
18.04.2016 22:38
Если я не правильно написал код, скажите как должно быть, конкретно где ошибка(и)?
Ошибка в критике непричастных людей.

sabir писал(а):
19.04.2016 18:03
в файле vdso_standalone_test_x86.c, если я правильно понял, реализован вызов syscall с тремя аргументами, строки 40 - 54:
Там реализовано три примера входа в ядро: через традиционное 0x80-е прерывание, syscall и vDSO.
Спасибо сказали:
Аватара пользователя
s.xbatob
Сообщения: 1139
ОС: Fedora

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение s.xbatob »

sabir писал(а):
18.04.2016 22:38
serzh-z писал(а):
18.04.2016 13:23
О чем это всё

Как написано выше, это все о том, как писать программы на С без libc, другой вопрос зачем и кому это надо. Это надо мне и всем тем, для кого такая возможность предусмотрена разрабами.

Зачем? Это нужно при сборке ядра. Все остальные случаи смахивают на мазохизм. Даже когда я в старые времена программировал железки с 4 Мб флешки - libc туда влезал.
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu
Контактная информация:

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение serzh-z »

Я понял, что автор имел в виду под этим:
sabir писал(а):
17.04.2016 18:32
Проблема в том, что вменяемого множества букв на тему встроенного асма в гугле я не нашел, с примерами таже ситуация, мне было интересно, как вызвать syscall, ежели число аргументов больше 3-х, а именно:
Речь шла про макроязык встраиваемого ассемблера/оптимизатора GCC: https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html
Спасибо сказали:
yoshakar
Сообщения: 259
ОС: Debian Stretch

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение yoshakar »

yoshakar писал(а):
20.04.2016 01:45
Самый простой способ — прилинковать libc статически.
С mmap примера я не выдам, ибо вызов сложный и разбираться с ним неохота. Я попроще вызов возьму:

Shell

~ % cat 1.c #include <unistd.h> void _start(void) { write(0, "hi\n", 4); _exit(0); } ~ % cc -O3 -static -nostartfiles 1.c -o 1 ~ % ./1 hi ~ % readelf -d 1 There is no dynamic section in this file. ~ % ls -l 1 -rwxrwxr-x 1 main main 2.9K Apr 21 00:33 1 ~ %

А если ипользовать syscall (2) вместо write и _exit, то получается вообще 1.9K,
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu
Контактная информация:

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение serzh-z »

yoshakar
Но libc прилинкована статически, чего ТС не хотел бы. =) См. `ar 1`.
Спасибо сказали:
yoshakar
Сообщения: 259
ОС: Debian Stretch

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение yoshakar »

serzh-z писал(а):
21.04.2016 01:11
Но libc прилинкована статически, чего ТС не хотел бы. =)
Как известно, бинарник со статически прилинкованной libc во всём подобен бинарнику без libc, только с libc. Поскольку мы пользуемся только системными вызовами, то в варианте с syscall там невероятно жалкие ошмётки от libc остаются (да и в приведённом варианте лишь чуть побольше),

P.S. `ar 1` у меня не работает, или я не понял, что имелось в виду.
Спасибо сказали:
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение sabir »

serzh-z писал(а):
20.04.2016 13:19
sabir писал(а):
19.04.2016 18:03
А меня, просто по приколу, т.к. я пишу на настоящем ассемблере, заинтересовал вопрос:
Мне тоже так показалось, поэтому и не понял какое отношение имеют какие-то там соглашения и пожелания от разрабочиков компиляторов к набору инструкций.

Я не понял Вашу мысль, выражайтесь яснее пожалуйста. Спасибо.
serzh-z писал(а):
20.04.2016 13:19
sabir писал(а):
19.04.2016 18:03
скажите кто ответственен за "constraints" во встроенный в GCC ассемблер, если не разрабы GCC, то кто?
Может быть разработчик конкретного процессора? =)

Т.е. Вы хотите сказать что разработчики процессора intel, например, ответственны за то, какими буквами "constraints" следует пользоваться во встроенном в GCC ассемблере? Даже если Вы правы, то критика "непричастных людей" все равно уместна, т.к. мне не удобно, что для регистров R10, R8, R9 нет своих "constraints", которые есть для регистров RAX, RDI, RSI и RDX. Значит во всем виноваты разрабы intel? Однако я по прежнему уверен и не отказываюсь от своих слов, что это косяк разрабов гцц. Почему так, объясняю:
предположим я хочу скомпилировать код в файле main.c. Делается это так:

Код: Выделить всё

cc -o main main.c

Вы с этим согласны? Да или нет?
Далее рассуждаем логически, мне плевать как именно происходит процесс компиляции, как парситься файл, передается ли что-нибудь GAS или нет, повторю, мне плевать, я вызываю программу СС, разрабами которой являются разарабы гцц, если код не правильный, то компилятор ДОЛЖЕН на stdout выдать сообщение от ошибке или предупреждение. Если я вместо "D", "S" и "d" напишу "Z", "X" и "y", то так и будет. Отсюда еще раз повторю свой вопрос:
Кто тот человек или группа лиц, который(ая) решает, что должны быть именно буквы "D", "S" и "d", а не "Z", "X" и "y" в конкретной реализации компилятора, я имею ввиду конкретно гцц. Вопрос лично к Вам.
serzh-z писал(а):
20.04.2016 13:19
sabir писал(а):
18.04.2016 22:38
Если я не правильно написал код, скажите как должно быть, конкретно где ошибка(и)?
Ошибка в критике непричастных людей.

Я задал вопрос об ошибке(ках) в приведенном мной коде, критика "непричастных людей", вероятно имеются ввиду разрабы гцц, была осуществлена за пределами собственно кода. Поэтому повторю вопрос, к коду имеются претензии? Да или нет?
serzh-z писал(а):
20.04.2016 13:19
sabir писал(а):
19.04.2016 18:03
в файле vdso_standalone_test_x86.c, если я правильно понял, реализован вызов syscall с тремя аргументами, строки 40 - 54:
Там реализовано три примера входа в ядро: через традиционное 0x80-е прерывание, syscall и vDSO.

Я опять не понял Вашу мысль, в строках 40-50, процитированы выше, я вижу ассемблерную вставку для вызова syscall, если Вы видите что то другое, расскажите что именно.
Спасибо сказали:
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение sabir »

yoshakar писал(а):
20.04.2016 01:45
sabir писал(а):
19.04.2016 16:52
А разве можно вызвать syscall без ассемблера, я гуглил по этому вопросу, но ничего не нашел, если Вам не сложно, запостите простой пример вызова sys_mmap, например, на любом ЯВУ, без ассемблера и без каких-либо библиотек, мне бы пригодилось
Можно. Самый простой способ — прилинковать libc статически.

Нельзя. Как правильно было замечено serzh-z:
serzh-z писал(а):
21.04.2016 01:11
Но libc прилинкована статически, чего ТС не хотел бы. =)

Именно так, я имел ввиду прямой вызов syscall из ЯВУ, без ассемблерной вставки, динамической или статической линковли с левыми либами, ключая libc.
Спасибо сказали:
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение sabir »

s.xbatob писал(а):
20.04.2016 14:46
sabir писал(а):
18.04.2016 22:38
serzh-z писал(а):
18.04.2016 13:23
О чем это всё

Как написано выше, это все о том, как писать программы на С без libc, другой вопрос зачем и кому это надо. Это надо мне и всем тем, для кого такая возможность предусмотрена разрабами.

Зачем? Это нужно при сборке ядра. Все остальные случаи смахивают на мазохизм. Даже когда я в старые времена программировал железки с 4 Мб флешки - libc туда влезал.

Затем что Linux это ядро, только ядро и ничего кроме ядра. Доказательство:
www.kernel.org
Все что не ядро или как минимум не модуль ядра, то не Linux, включая libc и все её производные. На всякий случай ещё раз публично поясню свою позицию: libc не входит в ядро, а значит не является Linux, да libc это чаcть дистрибутива Linux, но не Linux как таковой.
Сколько нибудь продуктивное программирование под ядро = Linux невозможно без вызова syscall'ов, поэтому их вызов напрямую обязателен, для меня. И еще раз с удовольствием публично повторю, для меня Linux это только ядро, ВСЕ остальные либы и бинари всего лишь более или менее нужные или не нужные левые (GNU) включения
Спасибо сказали:
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение sabir »

yoshakar писал(а):
21.04.2016 00:37
yoshakar писал(а):
20.04.2016 01:45
Самый простой способ — прилинковать libc статически.
С mmap примера я не выдам, ибо вызов сложный и разбираться с ним неохота. Я попроще вызов возьму:

Shell

~ % cat 1.c #include <unistd.h> void _start(void) { write(0, "hi\n", 4); _exit(0); } ~ % cc -O3 -static -nostartfiles 1.c -o 1 ~ % ./1 hi ~ % readelf -d 1 There is no dynamic section in this file. ~ % ls -l 1 -rwxrwxr-x 1 main main 2.9K Apr 21 00:33 1 ~ %

А если ипользовать syscall (2) вместо write и _exit, то получается вообще 1.9K,

У меня получается:

Код: Выделить всё

~$ cc -O3 -static -nostartfiles 1.c -o 1
/usr/lib64/gcc/x86_64-slackware-linux/4.8.2/../../../../x86_64-slackware-linux/bin/ld: cannot find -lgcc_eh

Лечиться как:

Код: Выделить всё

# cd /usr/lib64/gcc/x86_64-slackware-linux/4.8.2
# ln -sf libgcc.a libgcc_eh.a

далее делаем:

Код: Выделить всё

objdump -d ./1

и видим наличие "<__libc_*" включений, значит это статическая линковка с libc, не катит

А если заюзать приведенны мной выше пример кода:

Код: Выделить всё

#include <sys/types.h>

#define sys_write            1
#define sys_exit            60

void exit(int code)
{
    __asm__ __volatile__(
        "syscall"
        :
        : "a"(sys_exit), "D"(code)
        : "cc", "rcx", "r11", "memory");
    __builtin_unreachable(); // syscall above never returns
}

ssize_t write(int fd, const void * buf, size_t size)
{
    ssize_t result;
    __asm__ __volatile__(
        "syscall"
        : "=a"(result)
        : "a"(sys_write), "D"(fd), "S"(buf), "d"(size)
        : "cc", "rcx", "r11", "memory");
    return result;
}

void _start()
{
    write(1, "Hi\n", 3);
    exit(0);
}

да скомпилить его как:

Код: Выделить всё

cc -Wall -s -nostdlib -march=native -pipe -O2 -Os -mfpmath=sse -std=c99 -o main main.c

а потом:

Код: Выделить всё

objdump -d ./main

то получим:

Код: Выделить всё

./main:     file format elf64-x86-64

Disassembly of section .text:

00000000004000e8 <.text>:
  4000e8:    b8 3c 00 00 00           mov    $0x3c,%eax
  4000ed:    0f 05                    syscall
  4000ef:    b8 01 00 00 00           mov    $0x1,%eax
  4000f4:    0f 05                    syscall
  4000f6:    c3                       retq
  4000f7:    bf 01 00 00 00           mov    $0x1,%edi
  4000fc:    ba 03 00 00 00           mov    $0x3,%edx
  400101:    be 14 01 40 00           mov    $0x400114,%esi
  400106:    89 f8                    mov    %edi,%eax
  400108:    0f 05                    syscall
  40010a:    b8 3c 00 00 00           mov    $0x3c,%eax
  40010f:    40 30 ff                 xor    %dil,%dil
  400112:    0f 05                    syscall

944 байта, при желании можно еще много покоцать, никаких зависимостей, можно смело юзать заточенные под С структуры, именно последнее является проблемой, если кодить на голом асме, выравнивание, буть оно не ладно
Спасибо сказали:
yoshakar
Сообщения: 259
ОС: Debian Stretch

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение yoshakar »

sabir писал(а):
21.04.2016 07:38
и видим наличие "<__libc_*" включений, значит это статическая линковка с libc, не катит
objcopy --redefine-sym спасёт отца русской демократии. И в варианте с syscall у меня нет никаких libc, а у вас?

Shell

~ % cat 2.c #define _GNU_SOURCE #include <unistd.h> #include <sys/syscall.h> void _start(void) { syscall(SYS_write, 0, "hi\n", 4); syscall(SYS_exit, 0); } ~ % cc -O3 -static -nostartfiles 2.c -o 2 ~ % objdump -d 2 | grep libc ~ %


sabir писал(а):
21.04.2016 07:38
944 байта, при желании можно еще много покоцать
Так вам нужен бинарь минимальнейшего размера или системный вызов без библиотек? Для первого ассемблер нужен, для второго — нет.
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu
Контактная информация:

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение serzh-z »

sabir писал(а):
21.04.2016 06:35
Я не понял Вашу мысль, выражайтесь яснее пожалуйста. Спасибо.
sabir писал(а):
21.04.2016 06:35
это косяк разрабов гцц.
Я уже и ссылку на документацию, вроде бы, дал. Там прямо в первом абзаце описано назначение макрообозначений расширенного ассемблера GCC. Если есть такое большое желание выдать совсем непереносимый код, то нужно явно писать в шаблоне нечто типа "mov $0x1,%r8; syscall" и не пользоваться фичами расширенного ассемблера, которые автоматически выбирают регистры, в зависимости от целевого процессора.
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu
Контактная информация:

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение serzh-z »

sabir писал(а):
21.04.2016 07:38
944 байта, при желании можно еще много покоцать, никаких зависимостей, можно смело юзать заточенные под С структуры, именно последнее является проблемой, если кодить на голом асме, выравнивание, буть оно не ладно
Да, даёшь больше собственных реализаций libc, своих, хороших, уникальных, оптимизированных и разных, со своим набором оберток! =)
Спасибо сказали:
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение sabir »

yoshakar писал(а):
21.04.2016 11:33
И в варианте с syscall у меня нет никаких libc, а у вас?

Подтверждаю, в бинаре у меня тоже нет, а в Вашем коде есть. Объясню свою позицию, если запросить man 2 syscall, то можно увидеть
NAME top

syscall - indirect system call

Написано не прямой системный вызов, Вы согласны?
DESCRIPTION top

syscall() is a small library function

Написано syscall() это маленькая библиотечная функция, Вы согласны?
Из чего следует, что syscall() , это не системный вызов, а функция из библиотеки libc.so, в которой, в свою очередь, реализован прямой системный вызов.
Еще раз, функция syscall() находиться в библиотеке libc.so, в Вашем коде Вы вызываете функцию syscall() из библиотеки libc.so, Вы согласны?
А мне нужен прямой вызов системного (ядерного) вызова из ЯВУ.
yoshakar писал(а):
21.04.2016 11:33
Так вам нужен бинарь минимальнейшего размера или системный вызов без библиотек? Для первого ассемблер нужен, для второго — нет.

Нет мне не нужен бинарь минимальнейшего размера, а системный вызов без библиотек как раз таки нужен.
Еще раз акцентирую Ваше внимание, вызов библиотечной функции syscall() и прямой вызов syscall = system call = системный вызов это НЕ одно и тоже.
Так как же все таки быть с системным вызовом SYS_mmap, собственно из-за него я открыл эту дискуссию
Спасибо сказали:
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение sabir »

serzh-z писал(а):
21.04.2016 13:08
Я уже и ссылку на документацию, вроде бы, дал. Там прямо в первом абзаце описано назначение макрообозначений расширенного ассемблера GCC.

Вопрос был не об "описании назначений макрообозначений расширенного ассемблера GCC", а
sabir писал(а):
21.04.2016 06:35
Кто тот человек или группа лиц, который(ая) решает, что должны быть именно буквы "D", "S" и "d", а не "Z", "X" и "y" в конкретной реализации компилятора, я имею ввиду конкретно гцц. Вопрос лично к Вам.

В очередной раз вынужден напомнить, Вы опять не ответили на мои вопросы:
sabir писал(а):
18.04.2016 22:38
Если я не правильно написал код, скажите как должно быть, конкретно где ошибка(и)?

sabir писал(а):
21.04.2016 06:35
в строках 40-50, процитированы выше, я вижу ассемблерную вставку для вызова syscall, если Вы видите что то другое, расскажите что именно
Спасибо сказали:
yoshakar
Сообщения: 259
ОС: Debian Stretch

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение yoshakar »

sabir писал(а):
23.04.2016 20:49
Еще раз акцентирую Ваше внимание, вызов библиотечной функции syscall() и прямой вызов syscall = system call = системный вызов это НЕ одно и тоже.
Скажите, вы верите в заряженную воду и гомеопатию?
Спасибо сказали:
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение sabir »

yoshakar писал(а):
24.04.2016 11:30
sabir писал(а):
23.04.2016 20:49
Еще раз акцентирую Ваше внимание, вызов библиотечной функции syscall() и прямой вызов syscall = system call = системный вызов это НЕ одно и тоже.
Скажите, вы верите в заряженную воду и гомеопатию?

Прекрасный прямой вопрос. Этот вопрос лежит за пределами дискуссии, однако я все же отвечу. Нет, я не верю в заряженную воду и гомеопатию.
Я ответил на Ваш вопрос, теперь ответьте на мой:
sabir писал(а):
23.04.2016 20:49
Еще раз, функция syscall() находиться в библиотеке libc.so, в Вашем коде Вы вызываете функцию syscall() из библиотеки libc.so, Вы согласны?
Спасибо сказали:
yoshakar
Сообщения: 259
ОС: Debian Stretch

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение yoshakar »

sabir писал(а):
24.04.2016 18:42
Прекрасный прямой вопрос. Этот вопрос лежит за пределами дискуссии, однако я все же отвечу. Нет, я не верю в заряженную воду и гомеопатию.
Тогда вам стоит подумать над тем, что ваше нежелание использовать syscall из libc — это то же самое, что отказ пить воду, в которой в гомеопатической дозе растворён яд.
sabir писал(а):
24.04.2016 18:42
Еще раз, функция syscall() находиться в библиотеке libc.so, в Вашем коде Вы вызываете функцию syscall() из библиотеки libc.so, Вы согласны?
Никоим образом. Во-первых, не libc.so, а libc.a, раз уж используется статическая линковка. Во-вторых, когда я вызываю функцию, я вызываю функцию с именем syscall и прототипом, объявленным в соответствующих заголовочных файлах. Откуда эта функция возьмётся при этом не фиксируется никак. Это может быть syscall из libc.so, это может быть syscall из статически прилинкованной стандартной библиотеки, а может быть syscall из другого модуля моей же программы. Конкретно в моём случае это syscall из другого модуля моей программы — модуля syscall.o. Этот модуль по некоторым причинам запакован в libc.a, но хуже он от этого не становится, так что это частность, не имеющая отношения к делу.
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu
Контактная информация:

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение serzh-z »

sabir писал(а):
23.04.2016 21:22
В очередной раз вынужден напомнить, Вы опять не ответили на мои вопросы:
Предлагаю обратиться в Министерство Вопросов и написать на меня жалобу. Я, вроде, вообще не проявлял никакого интереса к вашему коду и не обещал искать в нём ошибки.
Спасибо сказали:
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Re: Есть ли жизнь за пределами libc.so или как писать на голом С

Сообщение sabir »

yoshakar писал(а):
24.04.2016 18:55
sabir писал(а):
24.04.2016 18:42
Еще раз, функция syscall() находиться в библиотеке libc.so, в Вашем коде Вы вызываете функцию syscall() из библиотеки libc.so, Вы согласны?
Никоим образом.

Shell

~$ nm -D /lib64/libc.so* | grep syscall 00000000000f4230 T syscall


yoshakar писал(а):
24.04.2016 18:55
Во-первых, не libc.so, а libc.a, раз уж используется статическая линковка. Во-вторых, когда я вызываю функцию...

Вы в любом случае вызываете функцию из библиотеки libc, а статичеки или динамически линкуется библиотека libc уже не важно.
Таким образом я остаюсь при своем мнении: Из кода языка высокого уровня осуществить прямой вызов "Linux kernel system call" невозможно, единственный способ это ассемблерная вставка, но это уже не ЯВУ.

Ну и раз уж в разделе "Программирование" начались разговоры о заряженной воде, предлагаю считать эту дискуссию завершенной.
Выражаю благодарность всем, кто принял участие и высказал свое мнение. Удачного кодинга.
Спасибо сказали:
Ответить