Всередині ядра Linux діє безліч угод, що вимагають багато чого прочитати і вивчити для розуміння їх використання та призначення. Цей розділ висвітлює неко-торие неясності або неточності використання С, фокусуючись на прийнятих З-соглаше-пах, використовуваних в ядрі Linux 2.6.
Незвичайне використання мови С
asmlinkage вказує компілятору передавати параметри в локальний стек. Це свя-зано з макросом FASTCALL, який вказує компілятору (апаратно-залежному) передавати параметри в регістри загального призначення. Ось макрос з include / asm / linkage, з:
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 часто вставляється в кінці чисельних констант для позначення «unsigned long». UL (або L для long) необхідно вставляти для того, щоб вказати компілятору вважати значення мають тип long 1. На деяких архітектурах таким чином можна хаті-жати переповнення і виходу за межі типу. Наприклад, 16-бітове ціле може пред-ставлять числа від -32768 до +32767; беззнаковое ціле може представляти числа від 0 до 65535. При використанні UL ви пишете не-залежний код для довгих чисел або довгих бітових масок.
Ось деякі демонструють це приклади з ядра:
18 idefine GOLDEN_RATIO_PRIME 0x9e37000lUL
23 #define ULONG_MAX (-OUL)
39 #define SLAB_POISON 0x00000800UL / * Отруйні об'єкти * /
1 Очевидно, мається на увазі unsigned long. Прим. науч. ред.
Глава 2 • Дослідницький інструментарій
Ключове слово inline необхідно для оптимізації виконання функцій, інтег-ріруя код цих функцій в викликає код. Ядро Linux використовує безліч inline-функцій, оголошених статичними; «Static тНпе» -функція змушує компілятор намагатися впроваджувати код функції в усі викликають її ділянки коду і, якщо це можли-но, уникати ассемблирования коду цієї функції. Іноді компілятор не може обійтися без ассемблирования коду (в разі рекурсій), але в більшості випадків функції, об'єк-явлені як static inline, повністю впроваджуються в викликає код.
Метою такого впровадження є усунення всіх зайвих операцій, що виконуються при виконанні функції. Вираз # define також дозволяє прибрати пов'язані з викликом функції операції і зазвичай використовується для забезпечення портіруемость на інші когось пілятори і вбудовані системи.
Так чому б не зробити вбудованими всі функції? Недоліком використання вбудовування є збільшення бінарного коду і іноді уповільнення доступу до кешу процесора.
Ці два ключових слова ігноруються багатьма початківцями програмістами. Ключі-ше слово const не слід розуміти як константу, а скоріше як тільки для читання. Наприклад, const int be - це покажчик на const-ціле. При цьому покажчик може бути змінений, а ціле число - немає. З іншого боку, int const * jc позначає const-покажчик на ціле, коли число може бути змінено, а покажчик - немає. Ось приклад використання const:
62 8 static inline void prefetch (const void * x)
630 __ asm____ volatile_ ( "debt 0,% 0". "R" (x));
Ключове слово volatile (тимчасовий) означає змінну, яка не може бути змінена без зауваження; volatile повідомляє компілятору, що йому потрібно перезавантажити позначену змінну кожен раз, коли вона зустрічається, а не збереженні-нять і отримувати доступ до її копії. Хорошим прикладом змінної, яку потрібно від-мітити як тимчасову, є змінні, пов'язані з перериваннями, апаратними регістрами, або змінні, що розділяються конкуруючими процесами. Ось приклад використання volatile:
include / linux / spinlock.h 51 typedef struct
Короткий огляд інструментарію для дослідження ядра
volatile unsigned int lock; 58> spinlock_t;
З огляду на те, що const слід трактувати як тільки для читання, ми бачимо, що не-які змінні можуть бути одночасно const і volatile (наприклад, змін-ва, що зберігає вміст регулярно оновлюваного апаратного регістра з доступом тільки для читання).
Цей короткий огляд дозволить початківцям хакерам ядра Linux відчувати себе впевненіше при вивченні вихідних кодів ядра.
Короткий огляд інструментарію для дослідження ядра
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Data: 2's complement, little endian
Version: 1 (current)
OS / ABI: UNIX - System V
Type: EXEC (Executable file)
Machine: Intel 80386
Entry point address: 0x8048310
Start of program headers: 52 (bytes into file)
Start of section headers: 10596 (bytes into file)
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:
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
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
Команда 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
Каже ядро: прослуховування повідомлень ядра
Утиліта run перераховує все символи, що знаходяться в об'єктному файлі. Вона відображає значення символів, їх тип і ім'я. Ця утиліта не так корисна, як інші, але тим не менш може бути корисна при налагодженні файлів бібліотек.
Команда аг, або archive (архівація), допомагає підтримувати індексовані біб-лиотека, використовувані компоновщиком. Команда аг збирає один або кілька об'єк-проектних файлів в одну бібліотеку. Крім цього, вона може виділяти окремий об'єкт-ний файл з бібліотеки. Найчастіше команду аг можна побачити в Make-файлі. Вона годину-то використовується для об'єднання використовуваних функцій в одну бібліотеку. Наприклад, припустимо, що у вас є функція, що виконує парсинг командного файлу і через потяг деяких даних або виклик для вилучення інформації для зазначених апаратних регістрів. Ця функція необхідна декільком виконуваним програмам. Архівування цієї функції в окрему бібліотеку полегшить вам контроль за версія-ми, помістивши функцію тільки в одне місце.