LinuxForum.Fans
Тема

Экспорт символов ядра

Автор: Olej 6 сообщений 7054 просмотров
#213258

есть у меня вопрос, который никак не пойму - нужна помощь!
вот есть символы (имена) ядра, в динамике:

text

[olej@notebook ~]$ cat /proc/kallsyms | head -n5
c0400000 T startup_32
c0400000 T _text
c0400079 t bad_subarch
c0400079 W xen_entry
c040007b t default_entry
[olej@notebook ~]$ cat /proc/kallsyms | wc -l
69698

как видно, их дофигища ... в других инсталляциях я получал и 80000 и т.п.
причём, это и имена ядра, и всех загруженных модулей:

text

[olej@notebook ~]$ cat /proc/kallsyms | tail -n3
f7e6b174 t cleanup_module    [output]
f7e6b0bb T video_output_register    [output]
f7e6b0a5 T video_output_unregister    [output]

Поскольку формат модуля ядра - это объектный файл, то разъяснение к формату таблицы имён нам лучшим образом даст:

text

[olej@notebook ~]$ man nm
...
       ·   The symbol type.  At least the following types are used; others are, as well, depending on the object file format.  [b]If lowercase, the
           symbol is local; if uppercase, the symbol is global (external).[/b]
           "A" The symbol’s value is absolute, and will not be changed by further linking.
           "B"
           "b" The symbol is in the uninitialized data section (known as BSS).
           "C" The symbol is common.  Common symbols are uninitialized data.  When linking, multiple common symbols may appear with the same
               name.  If the symbol is defined anywhere, the common symbols are treated as undefined references.
           "D"
           "d" The symbol is in the initialized data section.
           "G"
           "g" The symbol is in an initialized data section for small objects.  Some object file formats permit more efficient access to small
               data objects, such as a global int variable as opposed to a large global array.
           "i" The symbol is in a section specific to the implementation of DLLs.
           "N" The symbol is a debugging symbol.
           "p" The symbols is in a stack unwind section.
           "R"
           "r" The symbol is in a read only data section.
           "S"
           "s" The symbol is in an uninitialized data section for small objects.
           "T"
           "t" The symbol is in the text (code) section.
           "U" The symbol is undefined.
           "V"
           "v" The symbol is a weak object.  When a weak defined symbol is linked with a normal defined symbol, the normal defined symbol is
               used with no error.  When a weak undefined symbol is linked and the symbol is not defined, the value of the weak symbol becomes
               zero with no error.  On some systems, uppercase indicates that a default value has been specified.
           "W"
           "w" The symbol is a weak symbol that has not been specifically tagged as a weak object symbol.  When a weak defined symbol is linked
               with a normal defined symbol, the normal defined symbol is used with no error.  When a weak undefined symbol is linked and the
               symbol is not defined, the value of the symbol is determined in a system-specific manner without error.  On some systems,
               uppercase indicates that a default value has been specified.
...

- оно стоит того, чтобы цитировать полностью, а самое интересное - это выделил уже я. Итого, в качестве имён функций API, которые можно вызывать из кода модуля, нас должны интересовать: а). большими буквами (external) + б). в секции .text, т.е. - T.
Теперь меня интересуют обработчики sys_*() в таблице sys_call_table:

text

[olej@notebook ~]$ cat /proc/kallsyms | grep sys_call_table
c07ab3d8 R sys_call_table
[olej@notebook etc]$ cat /usr/include/asm/unistd_32.h | head -n20
#ifndef _ASM_X86_UNISTD_32_H
#define _ASM_X86_UNISTD_32_H

/* * This file contains the system call numbers. */

#define __NR_restart_syscall 0 #define __NR_exit 1 #define __NR_fork 2 #define __NR_read 3 #define __NR_write 4 #define __NR_open 5 #define __NR_close 6 #define __NR_waitpid 7 #define __NR_creat 8 #define __NR_link 9 #define __NR_unlink 10 #define __NR_execve 11 #define __NR_chdir 12 ...

Это было начало таблицы системных вызовов, и относительно них (только самый минимум но этого достаточно):

text

[olej@notebook ~]$ cat /proc/kallsyms | grep T | grep sys_open
c04deb28 T do_sys_open
c04dec0c T sys_openat
c04dec35 T sys_open
[olej@notebook ~]$ cat /proc/kallsyms | grep T | grep sys_close
c04dea99 T sys_close
#213261
Olej написал:
Это было начало таблицы системных вызовов, и относительно них (только самый минимум но этого достаточно):

Теперь сам вопрос (прошу прощения у модераторов за рваный постинг ... но уж много хочется сказать wink )

Делаем простейший модуль, проще не бывает:

text

#include <linux/module.h>
extern int sys_close( int fd );

static int __init sys_init( void ) { void* Addr; Addr = (void*)sys_close; printk( "sys_close address: %p\n", Addr ); return -1; }

module_init( sys_init );

Выполнение:

text

[olej@notebook sys_call_table]$ sudo insmod md_0c.ko 
insmod: error inserting 'md_0c.ko': -1 Operation not permitted
[olej@notebook sys_call_table]$ dmesg 
sys_close address: c04dea99

- на эту ошибку insmod не обращаем внимания, так задумано, а адрес замечательным образом совпадает с таблицей kallsyms.

Теперь в точности то же, но относительно другого обработчика:

text

#include <linux/module.h>
extern int sys_open( int fd );

static int __init sys_init( void ) { void* Addr; Addr = (void*)sys_open; printk( KERN_INFO "sys_open address: %p\n", Addr ); return -1; }

module_init( sys_init );

прототип sys_open() специально написан "липовый", потому как он не должен ни на что влиять!
Ещё при сборке увидим:

text

...
  MODPOST 2 modules
WARNING: "sys_open" [/home/olej/2011_WORK/LINUX-books/examples.DRAFT/sys_call_table/md_0o.ko] undefined!
  CC      /home/olej/2011_WORK/LINUX-books/examples.DRAFT/sys_call_table/md_0o.mod.o
  LD [M]  /home/olej/2011_WORK/LINUX-books/examples.DRAFT/sys_call_table/md_0o.ko
...

но модуль, естественно, собрался.
И :

text

[olej@notebook sys_call_table]$ sudo insmod md_0o.ko 
insmod: error inserting 'md_0o.ko': -1 Unknown symbol in module
[olej@notebook sys_call_table]$ dmesg
md_0o: Unknown symbol sys_open

Это уже куда серьёзнее! (это незагружаемый модуль)

Т.е., в итоге:
- имя sys_close - экспортируется ядром
- имя sys_open - не экспортируется ядром

Вот и вопрос:
Как узнать те имена, которые экспортируются ядром? (просматривать все исходники ядра на предмет export - не предлагать! : этим вы занимайтесь сами wink )

#213302

есть scripts/export_report.pl
не пойдёт?

#213303
Fat-Zer написал:
есть scripts/export_report.pl
не пойдёт?

1. "есть" - это где? у кого? wink как воспользоваться?

2. возможно и подойдёт ... только он даёт эти экспортируемые имена динамически? или статически где-то сохранеённые?
так же как отличаются:

text

[olej@notebook ~]$ cat /proc/kallsyms | grep sys_call_table
c07ab3d8 R sys_call_table
[olej@notebook ~]$ cat /boot/System.map-2.6.32.9-70.fc12.i686.PAE | grep sys_call_table
c07ab3d8 R sys_call_table

- значение одно и то же, но 1-е - динамическое, 2-е - статическое.

3. и, наконец, меня интересует не только (и даже не столько) сами экспортируемые символы, как ответ на вопрос выше: почему из символов, отображаемых как глобальные для линковки, одни разрешаются (sys_close), а другие нет (sys_open).

#213311
Olej написал:
1. "есть" - это где? у кого? как воспользоваться?

scripts/export_report.pl - путь в дереве исходников ядра.
в общем он только форматирует содержимое Module.symvers (создаётся после сборки или конфигурации ядра). в общем см. код - там простой perl-скрипт

#213322
Fat-Zer написал:
есть scripts/export_report.pl
не пойдёт?

И подойдёт ... и не подойдёт :rolleyes:
В общем, это действительно формирование файла Module.symvers при начальном конфигурировании дерева исходников перед сборкой...

text

[olej@notebook scripts]$ perl export_report.pl -h
Usage: export_report.pl -h -k Module.symvers  [ -o outputfile ]
        -f: treat all the non-option argument as .mod.c files. Recommend using this as the last option
        -h: print detailed help
        -k: the path to Module.symvers file. By default uses the file from the current directory
        -o outputfile: output the report to outputfile

Тогда я просто могу посмотреть файл Module.symvers, сгенерированный после какой-то давней сборки ядра

text

[olej@notebook linux]$ cat Module.symvers | grep sys_close
0x00000000      sys_close       vmlinux EXPORT_SYMBOL

[olej@notebook linux]$ cat Module.symvers | grep sys_open

[olej@notebook linux]$ cat Module.symvers | grep sys_call_table

[olej@notebook linux]$ cat Module.symvers | grep sys_ 0x00000000 sys_close vmlinux EXPORT_SYMBOL 0x00000000 sys_copyarea vmlinux EXPORT_SYMBOL 0x00000000 generic_subsys_pm_ops vmlinux EXPORT_SYMBOL_GPL 0x00000000 fb_sys_write vmlinux EXPORT_SYMBOL_GPL 0x00000000 nfnetlink_subsys_register net/netfilter/nfnetlink EXPORT_SYMBOL_GPL 0x00000000 sys_imageblit vmlinux EXPORT_SYMBOL 0x00000000 sys_fillrect vmlinux EXPORT_SYMBOL 0x00000000 nfnetlink_subsys_unregister net/netfilter/nfnetlink EXPORT_SYMBOL_GPL 0x00000000 sys_tz vmlinux EXPORT_SYMBOL 0x00000000 fb_sys_read vmlinux EXPORT_SYMBOL_GPL

Это годится в качестве справки, здесь есть sys_close и нет sys_open ... - это подтверждение сказанного раньше, но я это уже и так знаю (хоть и гораздо более противным путём: модули там собирать... wink ).
Кроме того, это глухая статика: файл, сгенерированный много месяцев назад, так и лежит ... показывает имена экспортированные, но экспортированные ядром и подключенными модулями что были на момент сборки ядра ... никакие более поздние установки модулей там никак не отображаются.

Когда make в процессе сборки модуля (см. раньше) пишет:

text

WARNING: "sys_open" [/home/olej/2011_WORK/LINUX-books/examples.DRAFT/sys_call_table/md_0o.ko] undefined!

- то он для определения разрешённых-неразрешённых внешних имён использует заведомо не эту информацию из этого файла!
А откуда?

Войдите или зарегистрируйтесь, чтобы ответить.