Как найти время создания elf файла
Перейти к содержимому

Как найти время создания elf файла

  • автор:

Формат ELF-файла

В результате компиляции и компоновки ассемблером GAS создается файл формата ELF (Executable and Linkable Format), который содержит всю информацию, необходимую операционной системе для загрузки и запуска программы. Условно файл ELF состоит из трех частей:

  • Заголовок файла ELF
  • Заголовки программы
  • Заголовки разделов

Инструменты Arm GNU Toolchain предоставляют специальную утилиту для исследования ELF-файла — readelf . Мы ее можем найти в той же папке, где и располгааются исполняемые файлы компилятора gcc для arm64:

Утилита readelf в Arm GNU Toolchain

Например, в пакете Arm GNU Toolchain aarch64-none-elf эта утилита называется aarch64-none-elf-readelf . Передавая этой утилите различные параметры, можно получить представление различных частей файла в формате ELF. Для получения полной справки по данной утиилите ей надо передать опцию -H . Отмечу лишь некоторые основные опции, которые мы можем использовать для исследования файла в формате ELF:

  • -a или —all : вывод всей информации, аналогично применению опций -h -l -S -s -r -d -V -A -I
  • -h или —file-header : вывод заголовка файла
  • -l или —program-headers : вывод заголовков программы
  • -S или —section-headers (либо —sections ): вывод заголовков разделов
  • -g или —section-groups : вывод групп разделов
  • -t или —section-details : вывод информации о разделах
  • -e или —headers : вывод всех заголовков, эквивалентно набору опций -h -l -S
  • -s или —syms : вывод таблицы символов

Рассмотрим на примере простейшей программы, которая выводит приветственное соощение на консоль. Допустим, у нас есть файл hello.s со следующим кодом:

.global _start // устанавливаем стартовый адрес программы _start: mov X0, #1 // 1 = StdOut - поток вывода ldr X1, =hello // строка для вывода на экран mov X2, #19 // длина строки mov X8, #64 // устанавливаем функцию Linux svc 0 // вызываем функцию Linux для вывода строки mov X0, #0 // Устанавливаем 0 как код возврата mov X8, #93 // код 93 представляет завершение программы svc 0 // вызываем функцию Linux для выхода из программы .data hello: .ascii "Hello METANIT.COM!\n" // данные для вывода

Скомпилируем из этого файла объектный файл:

aarch64-none-elf-as hello.s -o hello.o

Затем из скомпилированного объектного файла hello.o создадим бинарный файл в формате ELF:

aarch64-none-elf-ld hello.o -o hello.so

Итак, мы получили бинарный исполныемый файл hello.so в формате ELF. Теперь проанализируем его.

Заголовок файла ELF

Для получения заголовка выполним команду

aarch64-none-elf-readelf -h hello.so

В результате мы должны получить вывод наподобие следующего:

c:\arm>aarch64-none-elf-readelf -h hello.so ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: AArch64 Version: 0x1 Entry point address: 0x400000 Start of program headers: 64 (bytes into file) Start of section headers: 66152 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 2 Size of section headers: 64 (bytes) Number of section headers: 6 Section header string table index: 5 c:\arm>

Это и есть заголовок программы. Разберем его.

Вначале идет поле Magic . Оно всегда имеет размер 16 байт и призван указать, что файл является корректным файлом ELF. Это поле всегда начинается с байта 0x7f , за которым следуют 3 байта, соответствующие символам «ELF» из таблицы ASCII .

Поле Class указывает на разрядность. Значение ELF64 говорит, что файл использует 64-разрядный формат. В 32-разрядных программах это поле имело бы значение ELF32 .

Поле Data сообщает операционной системе и загрузчику, в каком порядке должны считываться поля файла ELF — big-endian (обратный порядок) или little-endian (прямой порядок). Файлы ELF на Arm обычно используют кодировку little-endian для самого формата файла ELF.

Поле Version указывает на версию файла.

Поле Type указывает на тип файла

Поле Machine сообщает загрузчику, для какого типа процессоров предназначена программа. Наша 64-битная программа устанавливает в этом поле значение AArch64, указывая, что файл ELF будет работать только на 64-битных процессорах Arm. В случае с 32-разрядной программой это поле имело бы значение ARM , что означало бы, что она работает только на 32-разрядных процессорах Arm.

Поле Entry point address сообщает загрузчику, где находится точка входа программы. Когда программа была подготовлена в памяти операционной системой или загрузчиком и готова начать выполнение, это поле указывает, откуда начинать выполнение программы. В данном случае это адрес 0x400000 — стандартный адрес для ARM64.

Поле Flags указывает дополнительную информацию, которая может понадобиться загрузчику. Это поле зависит от архитектуры. В 64-битной программе, например, не определены флаги, зависящие от архитектуры, и это поле всегда будет содержать нулевое значение 0x0 . Для 32-битной программы это поле может принимать ряд значений, которые информируют, что программа ожидает аппаратную поддержку операций с плавающей запятой:

  • EF_ARM_ABIMASK (0xff000000) : старшие 8 бит значения содержат версию ABI, которая применяется файлом ELF. В настоящее время этот старший байт должен содержать значение 5 (т. е. 0x05000000), что означает, что файл ELF использует версию EABI 5.
  • EF_ARM_BE8 (0x00800000) : файл ELF содержит код BE-8 для выполнения на процессоре Arm v6. Этот флаг должен быть установлен только для исполняемого файла.
  • EF_ARM_ABI_FLOAT_HARD (0x00000400) : указывает, что файл соответствует стандарту вызова аппаратных процедур с плавающей точкой и что процессор будет Armv7 или выше и будет поддерживать аппаратное расширение VFP3-D16 с плавающей точкой.
  • EF_ARM_ABI_FLOAT_SOFT (0x00000200) : указывает, что файл соответствует стандарту программного вызова процедур с плавающей точкой. Операции с плавающей точкой обрабатываются через вызовы библиотечных функций.

Поле Size of this header описывает размер заголовка файла.

Остальные поля описывают расположение и количество заголовков программы и разделов в файле:

  • Start of program headers : начало заголовков программы
  • Start of section headers : начало заголовков разделов
  • Size of program headers : размер заголовков программы
  • Number of program headers : количество заголовков программы
  • Size of section headers : размер заголовков разделов
  • Number of section headers : количество заголовков разделов

Загрузчик использует эти поля для подготовки ELF-файла в памяти к выполнению.

Как создать объектный ELF файл с кодом?

Я пишу свой ассемблер RISC-V для Linux на Си. Мне нужно создать объектный ELF файл со сгенерированными машинными инструкциями. Мне нужно знать структуру файла: какие секции нужно создать, в какие поместить код. Где можно узнать больше по этой теме?

Отслеживать
задан 23 ноя 2023 в 16:52
13 3 3 бронзовых знака
В документации по формату ELF.
23 ноя 2023 в 18:20

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

можете посмотреть в wiki по ельфу документацию,или исходники вот.

довольно хороший пример на си,кстати там же и найдете генерацию исполняемого Тут врядли дадут полный пример в одном сообщении,уж больно много кода Вкратце,нужно создать секции text,,debug,init,fini,symtab,bss,data,и другие связаные с tab. Неинициализированые данные надо в bss,исполняемый код в text,инициализированые данные в data,а symtab еще не разобрался,debug если надо отладочные символы,init содержит инициализацию runtime , fini содержит runtime finish некоторые секции отсутсвуют в object files например в обьектных файлах нету final metadata,relocation table. Узнать еще можно в ibm wiki Удачного создания компилятора!

Строение ELF-файлов⚓︎

ELF — сокращение от «Executable and Lincable Format» — формат исполняемых и связываемых файлов. ELF определяет их структуру. Данная спецификация позволяет UNIX-подобным(/образным) системам правильно интерпретировать содержащиеся в файле машинные команды. Используется во многих операционных системах: GNU/Linux, FreeBSD, Solaris, etc.

Понимание строения ELF файла может редко пригодиться, но, тем не менее, оно будет полезно для понимания процесса разработки программного обеспечения, поиска дыр в безопасности и обнаружения подозрительных программ или файлов.

Начальное строение⚓︎

ELF файл

Для начала создадим директорию, в которой будут расположены тестовые программы, на которых будем «упражняться»:

 mkdir ~/LinuxPrograms cd ~/LinuxPrograms 

Типы⚓︎

Есть несколько типов ELF файлов (см. таблицы в конце статьи): * Перемещаемый файл — хранит инструкции (и данные), которые могут быть связаны с другими объектными файлами. Результатом может быть объектный или исполняемый файл. Так же к этому типу относятся объектные файлы статических библиотек. * Разделяемый объектный файл — также как и первый тип, содержит инструкции и данные, может быть связан с другими перемещаемыми и разделяемыми объектными файлами, в результате чего будет создан новый объектный файл, либо же при запуске программы ОС может динамически связывать его с исполняемым файлом программы , в результате чего будет создан исполняемый образ программы (в посл. случае речь идёт о разделяемых библиотеках). * Исполняемый файл — содержит полное описание, позволяющее ОС создать образ процесса. В т.ч.: инструкции, данные, описания необходимых разделяемых объектных файлов и др.

Для того, чтобы вывод всех команд, приведённых ниже, был краток, прост и понятен, напишите какую-нибудь простейшую программу, в которой нет ничего лишнего, что затраднит чтение:

 vim simple.c int main()  return(0); > 

И скомпилируйте её:

 gcc -o simple simple.c 

Убедитесь в том, что это ELF файл:

 file simple 

Структура у каждого файла может различаться. Грубо говоря, ELF файл состоит из: * Заголовка * Данных

Подробнее: * Таблица заголовков программы: 0 или более сегментов памяти (только в исполняемом файле). Сообщает, как исполняемый файл должен быть помещён в виртуальную память процесса. Это необходимо для образа процесса, исполняемых файлов и общих объектов. Для перемещаемых объектных файлов это не требуется. * Таблица заголовков разделов: 0 или более разделов. Сообщает, как и куда нужно загрузить раздел. Каждая запись раздела в таблице содержит название и размер раздела. Таблица заголовков раздела должна использоваться для файлов, используемых при редактировании ссылок. * Данные: тпблицы заголовка программы или раздела * Заголовок ELF (54/64 байта для 32/64 бит): определяет использование 32/64 бит (смотреть struct Elf32_Ehdr / struct Elf64_Ehdr в /usr/include/elf.h ) * Заголовок программы: как создать образ процесса. Используются во время выполнения. Сообщают ядру или компоновщику время выполнения ld.so , что загружать в память и как найти информацию о динамической компоновке. * Заголовок разделов: используются во время компоновки или компиляции. Сообщают редактору ссылок ld , как разрашать символы и как группировать похожие потоки байтов из разных двоичных объектов ELF.

  • Разделы — самые мелкие неделимые единицы в ELF файле, которые могут быть обработаны. Разделы содержат основную часть информации об объектных файлах для представления связывания. Эти данные включают инструкции, таблицу символов и информацию о перемещении. (просмотр ссылок)
  • Сегменты — наименьшие отдельные единицы, которые могут быть отображены в памяти с помощью exec или компоновщика. (исполняемые)

Разделы и сегменты не имеют определённого порядка в ELF. Только заголовок имеет фиксированную позицию.

При помощи утилиты readelf можно просмотреть основную информацию о файле.

Эта утилита входит в состав пакета binutils , поэтому ничего доустанавливать не надо.

Основные возможности readelf :

    Просмотр заголовка файла:

 readelf -h simple 
 readelf -S -W simple 
 readelf -s -W simple 

Как посмотреть дату создания файла в Linux

В системе Linux в свойствах файла файлового менеджера отображается только информация о дате последнего обращения к нему и дате изменения. Но вот дата создания там отсутствует. При этом иногда нужно посмотреть именно ее, например, чтобы узнать, с какого момента ведется запись лога. В этой инструкции расскажем, как посмотреть какие данные хранятся в файловых системах Linux и объясним, как узнать дату создания файла Linux . Будут упомянуты сразу же два удобных способа, каждый из которых со своими особенностями.

Дата создания файла

В стандарте POSIX прописаны только 3 вида временных меток, которые должна хранить файловая система:

  • atime – время последнего обращения к файлу.
  • mtime – время последнего изменения содержимого.
  • ctime – время последней модификации прав доступа или владельца.

Поэтому в старых файловых системах посмотреть информацию о дате создания файла зачастую невозможно. А вот в современных файловых системах (ext4, zfs, XFS и т. д.) она уже сохраняется.

Данные о дате создания записываются в специальном поле:

  • Ext4 – crtime
  • ZFS – crtime
  • XFS – crtime
  • Btrfs – otime
  • JFS – di_otime

Известно две методики просмотра этой информации: с помощью утилиты stat и debugfs. Однако первый метод подойдет пользователям не каждого дистрибутивов Linux. Второй способ – универсальный, но не такой простой в использовании. Разберемся с каждым из них по отдельности.

Используем Stat

Утилита stat выводит подробные сведения о файле. В том числе выводится дата создания файла Linux. Для ее запуска в терминале достаточно указать путь к файлу. Для примера посмотрим информацию про изображение pic_1.jpeg, хранящееся в каталоге /home/root-user/Pictures:

Необходимая информация записана в графе Создан. А с помощью опции -c получится задать определенные правила форматирования для вывода информации, например, оставив только нужную графу:

Как посмотреть дату создания файла в Linux

Но есть одна небольшая трудность. На некоторых дистрибутивах Linux при использовании утилиты stat это поле будет пустым.

Как посмотреть дату создания файла в Linux

Основная причина заключается в том, что выводимая информация отображается в в statx(2). Оболочка была добавлена в библиотеку glibc версии 2.28. То есть поддержка этой оболочки появилась в наборе базовых системных утилит GNU coreutils 8.31. Чтобы проверить версию, следует выполнить такую команду:

Как посмотреть дату создания файла в Linux

Следовательно, stat сможет выводить данные о создании файла только при наличии конкретных условий, которые были описаны выше. Например, в дистрибутиве Ubuntu 21.10 все работает без каких-либо проблем, а в Ubuntu 20.04 поле будет пустым.

Используем DebugFS

Утилита DebugFS не имеет ограничений по версии. Она будет работать всегда. Но и процедура использования у нее несколько более запутанная. Связано это с тем, что для просмотра даты создания файла через debugfs, нужно узнать номер его inode и файловую систему. Получить inode выйдет с помощью команды ls с опцией -i, указав путь к файлу:

$ ls -i /home/root-user/scripts/main_script.txt

Как посмотреть дату создания файла в Linux

Для просмотра файловой системы пригодится команда df:

Как посмотреть дату создания файла в Linux

Теперь все нужные данные собраны, и можно переходить к использованию утилиты debugfs. Ей нужно передать опцию -R, указать номер inode, а затем название файловой системы:

Как посмотреть дату создания файла в Linux

После этого в терминале вы сможете найти поле, в котором хранится дата создания. В нашем случае это crtime.

На этом инструкции завершена.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *