Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Необычное использование языка С
Внутри ядра Linux действует множество соглашений, требующих много чего прочитать и изучить для понимания их использования и назначения. Этот раздел освещает некоторые неясности или неточности использования С, фокусируясь на принятых С-соглаше-ниях, используемых в ядре Linux 2.6. Необычное использование языка С Asmlinkage asmlinkage указывает компилятору передавать параметры в локальный стек. Это связано с макросом FASTCALL, который указывает компилятору (аппаратно-зависимому) передавать параметры в регистры общего назначения. Вот макрос из include /asm/ linkage, с: include/asm/linkage.h 4 #define asmlinkage CPP_ASMLINKAGE _ attribute_ ((regparm(O) ) ) 5 #define FASTCALL(x) x_ attribute_ ((regparm(3))) 6 #define fastcall _ attribute_ ((regparm(3))) Далее представлен пример asmlinkage. asmlinkage long sys_gettimeofday (struct timeval _________ user *tv, struct timezone ___ user *tz) UL UL часто вставляется в конце численных констант для обозначения «unsigned long». UL (или L для long) необходимо вставлять для того, чтобы указать компилятору считать значение имеющим тип long1. На некоторых архитектурах таким образом можно избежать переполнения и выхода за границы типа. Например, 16-битовое целое может представлять числа от -32768 до +32767; беззнаковое целое может представлять числа от 0 до 65535. При использовании UL вы пишете архитектурно-независимый код для длинных чисел или длинных битовых масок. Вот некоторые демонстрирующие это примеры из ядра: include/linux/hash.h 18 idefine GOLDEN_RATIO_PRIME 0x9e37000lUL include/linux/kernel.h 23 #define ULONG_MAX (-OUL) include/linux/slab, h 39 #define SLAB_POISON 0x00000800UL /* Ядовитые объекты */ 1 Очевидно, имеется в виду unsigned long. Примеч. науч. ред. Глава 2 • Исследовательский инструментарий Inline Ключевое слово inline необходимо для оптимизации выполнения функций, интегрируя код этих функций в вызывающий код. Ядро Linux использует множество inline-функций, объявленных статическими; «static тНпе»-функция заставляет компилятор стараться внедрять код функции во все вызывающие ее участки кода и, если это возможно, избегать ассемблирования кода этой функции. Иногда компилятор не может обойтись без ассемблирования кода (в случае рекурсий), но в большинстве случаев функции, объявленные как static inline, полностью внедряются в вызывающий код. Целью такого внедрения является устранение всех лишних операций, выполняемых при вызове функции. Выражение # define также позволяет убрать связанные с вызовом функции операции и обычно используется для обеспечения портируемости на другие компиляторы и встраиваемые системы. Так почему бы не сделать встроенными все функции? Недостатком использования встраивания является увеличение бинарного кода и иногда замедление доступа к кешу процессора. Const и volatile Эти два ключевых слова игнорируются многими начинающими программистами. Ключевое слово const не следует понимать как константу, а скорее как только для чтения. Например, const int be - это указатель на const-целое. При этом указатель может быть изменен, а целое число - нет. С другой стороны, int const *jc обозначает const-указатель на целое, когда число может быть изменено, а указатель - нет. Вот пример использования const: include/asm-i3 86/processor.h 62 8 static inline void prefetch(const void *x) 629 { 630 __ asm____ volatile_ (" debt 0, %0" : : " r" (x) ); 631 } Ключевое слово volatile (временный) означает переменную, которая не может быть изменена без замечания; volatile сообщает компилятору, что ему нужно перезагрузить помеченную переменную каждый раз, когда она встречается, а не сохранять и получать доступ к ее копии. Хорошим примером переменной, которую нужно отметить как временную, являются переменные, связанные с прерываниями, аппаратными регистрами, или переменные, разделяемые конкурирующими процессами. Вот пример использования volatile: include/linux/spinlock.h 51 typedef struct { Короткий обзор инструментария для исследования ядра volatile unsigned int lock; 58 } spinlock_t; Учитывая то, что const следует трактовать как только для чтения, мы видим, что некоторые переменные могут быть одновременно const и volatile (например, переменная, хранящая содержимое регулярно обновляемого аппаратного регистра с доступом только для чтения). Этот краткий обзор позволит начинающим хакерам ядра Linux чувствовать себя увереннее при изучении исходных кодов ядра. Короткий обзор инструментария для исследования ядра После успешной компиляции и сборки вашего ядра Linux вы можете захотеть посмотреть его «внутренности» до, после или даже во время процесса этой операции. Этот раздел коротко рассказывает об инструментах, используемых обычно для просмотра различных файлов ядра Linux. Objdump/readelf Утилиты objdump и readelf отображают информацию об объектных файлах (obj-dump) или ELF-файлах (readelf). С помощью аргументов командной строки вы можете использовать команды для просмотра заголовков, размера или архитектуры данного объектного файла. Например, вот дамп для ELF-заголовка простой С-программы (а. out), полученный с помощью флага -h readelf: Lwp> readelf -h a.out ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Intel 80386 Version: 0x1 Entry point address: 0x8048310 Start of program headers: 52 (bytes into file) Start of section headers: 10596 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Глава 2 • Исследовательский инструментарий Size of program headers: 32 (bytes) Number of program headers: 6 Size of section headers: 40 (bytes) Number of section headers: 29 Section header string table index: 2 6 А вот дамп заголовка программы, полученный с помощью readelf с флагом -1: Lwp> readelf -l a.out Elf file type is EXEC (Executable file) Entry point 0x8048310 There are 6 program headers, starting at offset 52 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Fig Align PHDR 0x000034 0x08048034 0x08048034 0x000c0 0x000c0 R E 0x4 INTERP 0x0000f4 0x080480f4 0x080480f4 0x00013 0x00013 R 0x1 [Requesting program interpreter: /lib/ld-linux.so.2] LOAD 0x000000 0x08048000 0x08048000 0x00498 0x00498 R E 0x1000 LOAD 0x000498 0x08049498 0x08049498 0x00108 0x00120 RW 0x1000 DYNAMIC 0x0004ac 0x080494ac 0x080494ac 0x000c8 0x000c8 RW 0x4 NOTE 0x000108 0x08048108 0x08048108 0x00020 0x00020 R 0x4 Section to Segment mapping: Segment Sections... 1.interp 2.interp.note.ABI-tag.hash.dynsym.dynstr.gnu.version.gnu.version_r rel.dyn.rel.plt.init.pit.text.fini.rodata 3.data.eh_frame.dynamic.ctors.dtors.got.bss 4.dynamic 5.note.ABI-tag Hexdump Команда hexdump отображает содержимое указанного файла в шестнадцатеричном, ASCII или восьмеричном формате. [Обратите внимание: на старых версиях Linux также использовался od (восьмеричный дамп). Теперь большинство систем используют вместо него hexdump.] Например, чтобы посмотреть первые 64 бита ELF-файла a.out в шестнадцатеричном режиме, нужно набрать следующее: Lwp> hexdump -x -n 64 a.out F 151c 0101 0001 0000 0000 0000 0000 0000010 0002 0003 0001 0000 8310 0804 0034 0000 0000020 2964 0000 0000 0000 0034 0020 0006 0028 OOld 001a 0006 0000 0034 0000 8034 0804 Говорит ядро: прослушивание сообщений ядра Обратите внимание на магическое число заголовка ELF (с поменянными местами байтами) по адресу 0x0000000. Это очень полезно при отладке действий; когда аппаратное устройство сбрасывает свое состояние в файл, обычный текстовый редактор интерпретирует его как набор управляющих символов. Hexdump позволяет вам увидеть, что же на самом деле содержится в файле без промежуточного преобразования редактором; hexdump - это редактор, который позволяет вам напрямую модифицировать файл без преобразования его содержимого в ASCII (или Unicode). Nm Утилита run перечисляет все символы, находящиеся в объектном файле. Она отображает значения символов, их тип и имя. Эта утилита не так полезна, как остальные, но тем не менее может быть полезна при отладке файлов библиотек. Objcopy Команда obj copy используется, когда вам нужно скопировать объектный файл и при этом пропустить или изменить некоторые его компоненты. Обычно objcopy используется для получения отладочных символов от тестируемого и работающего объектного файла. В результате размер объектного файла уменьшается и становится возможным его использование на встраиваемых системах. Аг Команда аг, или archive (архивация), помогает поддерживать индексированные библиотеки, используемые компоновщиком. Команда аг собирает один или несколько объектных файлов в одну библиотеку. Кроме этого, она может выделять отдельный объектный файл из библиотеки. Чаще всего команду аг можно увидеть в Make-файле. Она часто используется для объединения используемых функций в одну библиотеку. Например, предположим, что у вас есть функция, выполняющая парсинг командного файла и извлечение некоторых данных или вызов для извлечения информации для указанных аппаратных регистров. Эта функция необходима нескольким исполнимым программам. Архивирование этой функции в отдельную библиотеку облегчит вам контроль за версиями, поместив функцию только в одно место. Популярное:
|
Последнее изменение этой страницы: 2016-03-25; Просмотров: 696; Нарушение авторского права страницы