Форум программистов, компьютерный форум, киберфорум
Наши страницы
Evg
Войти
Регистрация
Восстановить пароль
Рейтинг: 3.00. Голосов: 2.

Прототип механизма инициализации в glibc и gcc

Запись от Evg размещена 14.06.2016 в 15:23
Обновил(-а) Evg 26.03.2017 в 19:50

Изначально предполагался ответ на вопрос из темы Книга по startup магии. Но текст получился объёмный, в итоге закинул в блог. Тут его по крайней мере можно подредактировать (если увижу ошибки), а так же добавить полезную информацию или даже довести до законченного состояния




Прототип, описывающий работу механизма инициализации glibc

Прототип реализован для системы команд x86 (т.е. 32-битный режим) для linux'а. Для других режимов или архитектур надо будет менять ассемблерную часть. Возможно, что в таком виде взлетит под windows, но не уверен. В некоторых прототипах присутствует конструкция asm ("строка"), она говорит о том, что в код функция должна попадать под именем "строка", т.е. без какого бы то ни было манглирования (под windows, например, компиляторы ко всем именам добавляют знак подчерка). Это нужно для гарантированного склеивания кода на Си и кода внутри ассемблерной вставки

Основой является функция my_init, расположенная в секции .my_init. Тело этой функции как бы размазано по нескольким объектным файлам. В каждом файле есть кусочек этой функции. Далее линкер при своей работе берёт в каждом объектном файле секцию .my_init и приклеивает к нему другие секции .my_init. Линкер понятия не имеет, что он собирает тело функции из отдельный частей. Он просто склеивает все секции .my_init из разных объектных файлов в одну общую секцию .my_init исполняемого файла и делает это по общим правилам склеивания секций. Чтобы функция my_init получилась "правильная", надо обеспечить, чтобы начало функции было в начале строки запуска линкера, а конец функции - в конце. Потому как линкер обрабатывает и склеивает файлы слева направо в соответствии с их порядком в командной строке. В обычном режиме работы, когда в gcc подаются пользовательские файлы, этот порядок обеспечивает сам gcc. Это легко можно увидеть, добавив в строку компиляции опцию -v (типа "gcc t.c -v"). Механизм финализации (т.е. вызов функции после завершения main, но до завершения работы программы) построен симметричным образом, я не стал его описывать

Предупреждаю сразу, что при реализации всяких конструкторов-деструкторов компилятор gcc напрямую НЕ использует данный механизм glibc. Поверх glibc'шного механизма компилятор gcc выстраивает второй уровень - компиляторный механизм. И в итоге только в одной точке подключает компиляторный механизм к glibc'шному механизму. Сделано это для того, чтобы можно было по простому прикручивать gcc не только к glibc'ям, но и к другим библиотекам, у которых какие-то свои собственные механизмы инициализации. Если не поленюсь, попозже опишу и его. Этот механизм сосредоточен в файлах crtbegin.o, crtend.o

ВНИМАНИЕ! Из-за ошибки форумного движка в тех ассемблерных вставках, где используется директива .section, написано "ax", хотя в тексте программы кавычки должны быть экранированы символами обратного слэша

C
/* Файл my_crt1.c */
 
/* Прототип glibc'шного модуля crt1.o */
 
#include <stdio.h>
 
extern void my_init (void) asm ("my_init");
extern void my_main (void);
 
/* Прототип настоящей точки входа (функции _start)
 * Считаем, что исполнение начинается как бы отсюда */
void my_start (void)
{
  printf ("my_start\n");
  my_init ();
  my_main ();
 
  /* Тут должен быть аналогичный вызов my_fini, но не стал его расписывать */
 
  /* После завершения работы main и my_fini должен быть вызван exit */
}
 
int main (void)
{
  my_start ();
  return 0;
}
C
/* Файл my_crti.c */
 
/* Прототип glibc'шного модуля crti.o */
 
/* Прототип glibc'шной функции _init, расположенной в секции .init
 * Начало тела функции my_init */
asm ("    .section .my_init, "ax", @progbits\n"
     "    .global my_init\n"
     "my_init:\n"
     "    push %ebp\n"
     "    mov  %esp,%ebp\n"
     "    sub  $0x8,%esp\n");
C
/* Файл my_crtn.c */
 
/* Прототип glibc'шного модуля crtn.o */
 
/* Конец тела функции my_init */
asm ("    .section .my_init, "ax", @progbits\n"
     "    leave\n"
     "    ret\n");
C
/* Файл t1.c */
 
/* Прототип пользовательского исходника */
 
#include <stdio.h>
 
/* Прототип функции main */
void my_main (void)
{
  printf ("my_main\n");
}
C
/* Файл t2.c */
 
/* Прототип пользовательского исходника */
 
#include <stdio.h>
 
extern void foo (void) asm ("foo");
 
void foo (void)
{
  printf ("foo\n");
}
 
/* Здесь мы встраиваемся в glibc'шный механизм инициализации,
 * мы описываем серединный фрагмент функции my_init */
asm ("    .section .my_init, "ax", @progbits\n"
     "    call foo\n");
C
/* Файл t3.c */
 
/* Прототип пользовательского исходника */
 
#include <stdio.h>
 
extern void bar (void) asm ("bar");
 
void bar (void)
{
  printf ("bar\n");
}
 
/* Здесь мы встраиваемся в glibc'шный механизм инициализации,
 * мы описываем серединный фрагмент функции my_init */
asm ("    .section .my_init, "ax", @progbits\n"
     "    call bar\n");
Запуск этого хозяйства. Не забываем, что порядок файлов в командной строке важен (для файлов crt)

Код:
$ gcc my_crt1.c my_crti.c t1.c t2.c t3.c my_crtn.c

$ ./a.out 
my_start
foo
bar
my_main
Ну и посмотрим глазками нашу чудо-функцию my_init. Как мы видим, она успешно склеилась из кусочков

Код:
$ objdump -d -j .my_init a.out

Disassembly of section .my_init:

080484b8 <my_init>:
 80484b8:       55                      push   %ebp           <--- my_crti.c
 80484b9:       89 e5                   mov    %esp,%ebp
 80484bb:       83 ec 08                sub    $0x8,%esp
 80484be:       e8 45 ff ff ff          call   8048408 <foo>  <--- t2.c
 80484c3:       e8 54 ff ff ff          call   804841c <bar>  <--- t3.c
 80484c8:       c9                      leave                 <--- my_crtn.c
 80484c9:       c3                      ret
Размещено в Без категории
Просмотров 627 Комментарии 0
Всего комментариев 0
Комментарии
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru