адреса ядра и приложения

Вопросы программного кода и архитектуры Linux

Модератор: Olej

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

адреса ядра и приложения

Непрочитанное сообщение Olej » 13 июн 2022, 21:13

Пришлось освежить и проверить, в связи с 64-бит системами.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: адреса ядра и приложения

Непрочитанное сообщение Olej » 13 июн 2022, 21:22

32 бит… Максимальный размер адресного пространства при 32-битных адресах равно 4Gb. В этом режиме в Linux принято решение разделить это адресное пространство между пользователем и ядром в соотношении 3:1. Границу M при этом указывает макрос-указатель current равный по умолчанию c0000000. Это константа периода компиляции, она может быть изменена, но путём пересборки ядра, что может иметь смысл (и имеет место) для некоторых аппаратных архитектур. Понятно, что адреса в приложениях пользователя будут выглядеть ниже этой границы, а адреса выше этой границы будут относится к ядру. Значение этой границы определяется (при сборке ядра) конфигурационным параметром CONFIG_PAGE_OFFSET :

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

$ uname -a
Linux orangepione 5.15.25-sunxi #22.02.1 SMP Sun Feb 27 09:23:25 UTC 2022 armv7l GNU/Linux

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

$ cat /boot/config-`uname -r` | grep CONFIG_PAGE_OFFSET
CONFIG_PAGE_OFFSET=0xC0000000
В примере показан реальный вывод в системе с процессором ARM, хотя в более ранней литературе можно встретить утверждение, что границей раздела для ARM является 0x80000000.

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

olej@orangepione:~$ inxi -Cxxx
CPU:       Topology: Quad Core model: ARMv7 v7l variant: cortex-a7 bits: 32 type: MCP arch: v7l 
           rev: 5 
           features: Use -f option to see features bogomips: 0 
           Speed: 1008 MHz min/max: 480/1008 MHz Core speeds (MHz): 1: 1008 2: 1008 3: 1008 4: 1008 

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

olej@orangepione:~$ lsb_release -a
No LSB modules are available.
Distributor ID:	Debian
Description:	Debian GNU/Linux 10 (buster)
Release:	10
Codename:	buster

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: адреса ядра и приложения

Непрочитанное сообщение Olej » 13 июн 2022, 21:23

64 бит… Всё становится гораздо веселее в Linux 64-бит. Прежде всего, когда мы говорим, временами, Intel X86_64 — это неверно, эту 64-бит спецификацию опубликовала в 2000 году фирма AMD, а Intel использует только лицензию AMD. Во-вторых, спецификация предполагает что для адресации используются только 48 (0-47) младших бит из 64, а старшие биты (48-63) расширяются битом 47 … подобно тому как это делается при расширении знакового разряда отрицательных целых. Эта спецификация адреса в сегодняшних процессорах поддерживается аппаратно. Это позволяет планировать лёгкость расширения в будущем до адресов 52, 57 и даже 64 бит (такие цифры называют в планах). В Linux 64-бит разделение виртуальных адресных пространств пользователь-ядро производится поровну, 1:1, по значению бита 47 (1 — ядро, 0 — пользовательский процесс). Поэтому адреса плоского адресного пространства для пользовательских процессов будут выглядеть как [000000000000000 — 00007fffffffffff), а для ядра будут выглядеть как [ffff800000000000 — ffffffffffffffff] (скобки квадратные и круглые в обозначении этих диапазонов означают, как это и принято в математике, «включая» и «исключая», соответственно). Как виртуальные 48-бит адреса затем аппаратно, с помощью MMU, преобразуются в физические адреса реальной памяти, нас на данном этапе не интересует. На интересует как они представляются. В этой модели памяти параметр конфигурации ядра CONFIG_PAGE_OFFSET не определяется — 48-битная граница фиксирована и в переопределении не нуждается:

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

$ cat /boot/config-`uname -r` | grep CONFIG_PAGE_OFFSET
$

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: адреса ядра и приложения

Непрочитанное сообщение Olej » 13 июн 2022, 21:30

Модуль aslr.c :

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

#include <linux/module.h>

MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Oleg Tsiliuric <olej.tsil@gmail.com>>");

static int __init my_init(void) {
        uint16_t d = 1234;
        void show(void* p) {
                printk("%20p%20px%20pK%20lx\n",
                       p, p, p, (uintptr_t)p);
        }
        if (IS_ENABLED(CONFIG_64BIT)) {
                printk("64-bit");
        }
        else {
                printk("32-bit");
        }
        printk("%20s%20s%20s%20s\n", "%p", "%px", "%pK", "int");
        show(&d);
#if defined(CONFIG_64BIT)
        show(printk);
#else
        show(_printk);
#endif
        show((void*)PAGE_OFFSET);
        show((void*)current);
        show((void*)0xffff800000000000);
        return -2;
}

module_init(my_init);
Приложение intptr.c :

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

#include <stdint.h>
#include <stdio.h>

static uint16_t d1 = 1234;
static uint16_t d2;

int main(void) {
        uint16_t d3 = 1234;
        printf("%20p%20p%20p\n", &d1, &d2, &d3);
        printf("%20lx%20lx%20lx\n",
               (uintptr_t)&d1,
               (uintptr_t)&d2,
               (uintptr_t)&d3);
        printf("%20llx%20llx%20llx\n",
               (long long unsigned int)&d1,
               (long long unsigned int)&d2,
               (long long unsigned int)&d3);
        return 0;
}

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

olej@R420:~/2022/own.BOOKs/BHV.kernel/examples/tools/aslr$ make
make -C /lib/modules/5.4.0-117-generic/build M=/home/olej/2022/own.BOOKs/BHV.kernel/examples/tools/aslr modules
make[1]: вход в каталог «/usr/src/linux-headers-5.4.0-117-generic»
  CC [M]  /home/olej/2022/own.BOOKs/BHV.kernel/examples/tools/aslr/aslr.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC [M]  /home/olej/2022/own.BOOKs/BHV.kernel/examples/tools/aslr/aslr.mod.o
  LD [M]  /home/olej/2022/own.BOOKs/BHV.kernel/examples/tools/aslr/aslr.ko
make[1]: выход из каталога «/usr/src/linux-headers-5.4.0-117-generic»
gcc -Wall intptr.c -o intptr
Система:

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

olej@R420:~/2022/own.BOOKs/BHV.kernel/examples/tools/aslr$ uname -a
Linux R420 5.4.0-117-generic #132-Ubuntu SMP Thu Jun 2 00:39:06 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

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

olej@R420:~/2022/own.BOOKs/BHV.kernel/examples/tools/aslr$ uname -a
Linux R420 5.4.0-117-generic #132-Ubuntu SMP Thu Jun 2 00:39:06 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

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

olej@R420:~/2022/own.BOOKs/BHV.kernel/examples/tools/aslr$ sudo insmod aslr.ko 
[sudo] пароль для olej:       
insmod: ERROR: could not insert module aslr.ko: Unknown symbol in module
Вот адреса kernel-space:

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

olej@R420:~/2022/own.BOOKs/BHV.kernel/examples/tools/aslr$ dmesg | tail -n6
[38452.016709]                   %p                 %px                 %pK                 int
[38452.016713]             b6b126a0    ffffb73546eebc56    ffffb73546eebc56    ffffb73546eebc56
[38452.016714]             ab07503d    ffffffff8348b926    ffffffff8348b926    ffffffff8348b926
[38452.016715]              9c02798    ffff8eb780000000    ffff8eb780000000    ffff8eb780000000
[38452.016715]             c35a2f8a    ffff8ec27c651740    ffff8ec27c651740    ffff8ec27c651740
[38452.016716]              75ed937    ffff800000000000    ffff800000000000    ffff800000000000
Вот адреса user-space:

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

olej@R420:~/2022/own.BOOKs/BHV.kernel/examples/tools/aslr$ ./intptr
      0x55a350dbf010      0x55a350dbf014      0x7ffd7e3470f6
        55a350dbf010        55a350dbf014        7ffd7e3470f6
        55a350dbf010        55a350dbf014        7ffd7e3470f6
Там особо интересные значения в 3-й колонке - локальная переменная в стеке - впритык к верхушке user-space рядом с началом kernel-space.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: адреса ядра и приложения

Непрочитанное сообщение Olej » 13 июн 2022, 21:46

Olej писал(а):
13 июн 2022, 21:30
Система:
32-бит ARM система:

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

olej@raspberrypi:~/2022/kernel/examples/tools/aslr $ uname -a
Linux raspberrypi 5.15.32-v7+ #1538 SMP Thu Mar 31 19:38:48 BST 2022 armv7l GNU/Linux

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

olej@raspberrypi:~/2022/kernel/examples/tools/aslr $ make
make -C /lib/modules/5.15.32-v7+/build M=/home/olej/2022/kernel/examples/tools/aslr modules
make[1]: вход в каталог «/usr/src/linux-headers-5.15.32-v7+»
  CC [M]  /home/olej/2022/kernel/examples/tools/aslr/aslr.o
  MODPOST /home/olej/2022/kernel/examples/tools/aslr/Module.symvers
  CC [M]  /home/olej/2022/kernel/examples/tools/aslr/aslr.mod.o
  LD [M]  /home/olej/2022/kernel/examples/tools/aslr/aslr.ko
make[1]: выход из каталога «/usr/src/linux-headers-5.15.32-v7+»
gcc -Wall intptr.c -o intptr
intptr.c: In function ‘main’:
intptr.c:10:14: warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 2 has type ‘unsigned int’ [-Wformat=]
   10 |  printf("%20lx%20lx%20lx\n",
      |          ~~~~^
      |              |
      |              long unsigned int
      |          %20x
   11 |         (uintptr_t)&d1,
      |         ~~~~~~~~~~~~~~
      |         |
      |         unsigned int
intptr.c:10:19: warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 3 has type ‘unsigned int’ [-Wformat=]
   10 |  printf("%20lx%20lx%20lx\n",
      |               ~~~~^
      |                   |
      |                   long unsigned int
      |               %20x
   11 |         (uintptr_t)&d1,
   12 |         (uintptr_t)&d2,
      |         ~~~~~~~~~~~~~~
      |         |
      |         unsigned int
intptr.c:10:24: warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 4 has type ‘unsigned int’ [-Wformat=]
   10 |  printf("%20lx%20lx%20lx\n",
      |                    ~~~~^
      |                        |
      |                        long unsigned int
      |                    %20x
......
   13 |         (uintptr_t)&d3);
      |         ~~~~~~~~~~~~~~  
      |         |
      |         unsigned int
intptr.c:15:9: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
   15 |         (long long unsigned int)&d1,
      |         ^
intptr.c:16:9: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
   16 |         (long long unsigned int)&d2,
      |         ^
intptr.c:17:9: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
   17 |         (long long unsigned int)&d3);
      |         ^

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

olej@raspberrypi:~/2022/kernel/examples/tools/aslr $ sudo insmod aslr.ko
insmod: ERROR: could not insert module aslr.ko: Unknown symbol in module

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

olej@raspberrypi:~/2022/kernel/examples/tools/aslr $ dmesg | grep "%p" -A5
[1223042.115782]                   %p                 %px                 %pK                 int
[1223042.115805]             de7b8fa7            8384fd8a            de7b8fa7            8384fd8a
[1223042.115835]             c6f80218            80a3df28            c6f80218            80a3df28
[1223042.115853]             1ab82f40            80000000            1ab82f40            80000000
[1223042.115870]              c2fe70d            95599f00             c2fe70d            95599f00
[1223042.115888]                    0                   0                   0                   0

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

olej@raspberrypi:~/2022/kernel/examples/tools/aslr $ ./intptr
             0x21028             0x2102c          0x7ee00396
               21028               2102c            7ee00396
               21028               2102c            7ee00396
Вот тут граница ядро-пользователь, как часто пишут относительно ARM = 0x80000000

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: адреса ядра и приложения

Непрочитанное сообщение Olej » 13 июн 2022, 21:50

Olej писал(а):
13 июн 2022, 21:46
32-бит ARM система:
Ещё одна ARM 32-бит система:

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

olej@orangepione:~/2022/kernel/examples.tmp/aslr$ uname -a
Linux orangepione 5.15.25-sunxi #22.02.1 SMP Sun Feb 27 09:23:25 UTC 2022 armv7l GNU/Linux

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

olej@orangepione:~/2022/kernel/examples.tmp/aslr$ sudo insmod aslr.ko
[sudo] пароль для olej: 
insmod: ERROR: could not insert module aslr.ko: Unknown symbol in module

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

olej@orangepione:~/2022/kernel/examples.tmp/aslr$ dmesg | tail -n6
[690891.041625]                   %p                 %px                 %pK                 int
[690891.041638]             682f0a8d            c25d1dc2            682f0a8d            c25d1dc2
[690891.041657]             6de3fc8a            c09c49a1            6de3fc8a            c09c49a1
[690891.041666]             6d66c095            c0000000            6d66c095            c0000000
[690891.041675]             bfcfa5e2            c438a440            bfcfa5e2            c438a440
[690891.041685]                    0                   0                   0                   0

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

olej@orangepione:~/2022/kernel/examples.tmp/aslr$ ./intptr
            0x501044            0x501048          0xbe9c042e
              501044              501048            be9c042e
              501044              501048    ffffffffbe9c042e
Тут отчётливо граница ядро-пользователь: 0xC0000000

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

olej@orangepione:~/2022/kernel/examples.tmp/aslr$ cat /boot/config-`uname -r` | grep CONFIG_PAGE_OFFSET
CONFIG_PAGE_OFFSET=0xC0000000

Ответить

Вернуться в «Linux изнутри»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 11 гостей