Русский
Русский
English
Статистика
Реклама

Перевод Почему usrbintest на 4Кб меньше, чем usrbin?



Пользователь с Reddit под ником mathisweirdaf поделился интересными наблюдениями:

 $ ls -lh /usr/bin/{test,[}-rwxr-xr-x 1 root root 59K  Sep  5  2019 '/usr/bin/['-rwxr-xr-x 1 root root 55K  Sep  5  2019  /usr/bin/test

[ и test должны быть псевдонимами друг друга, и все же между исполняющими их файлами из GNU coreutils наблюдается разница в 4Кб. Почему?

Во-первых, для всех, кого это удивило: да, существует /usr/bin/[. По этой теме у меня есть отдельная статья (англ.), но я все же коротко поясню:

Когда вы пишите if [ -e /etc/passwd ]; then .. эта скобка выступает не синтаксисом оболочки, а просто стандартной командой с забавным именем. Обычно она встроена в оболочку, но иногда может реализовываться через /usr/bin/[. Это объясняет многое из ее загадочного поведения, например, почему она чувствительна к пробелам: [1=2] оказывается не более валидно, чем ls-l/tmp.

Тем не менее откуда возникает разница в размере? Можно сравнить вывод objdump, чтобы увидеть, куда помещаются данные. Вот выдержка из objdump -h /usr/bin/[:

              size                                          offset15 .text         00006e82  0000000000002640  0000000000002640  00002640  2**416 .fini         0000000d  00000000000094c4  00000000000094c4  000094c4  2**217 .rodata       00001e4c  000000000000a000  000000000000a000  0000a000  2**5

А вот objdump -h /usr/bin/test:

15 .text         000068a2  0000000000002640  0000000000002640  00002640  2**416 .fini         0000000d  0000000000008ee4  0000000000008ee4  00008ee4  2**217 .rodata       00001aec  0000000000009000  0000000000009000  00009000  2**5

Здесь мы видим, что сегмент .text (скомпилированный исполняемый код) на 1504 байта больше, в то время как .rodata (постоянные значения и строки) больше на 864 байта.

Суть в том, что увеличенный размер сегмента .text вынуждает его перемещаться из 8000 в 9000, пересекая границу размера страницы 0х1000 (4096) и, следовательно, смещая все другие сегменты на 4096 байтов. Именно эту разницу в размере мы и наблюдаем.

Единственное номинальное отличие между [ и test в том, что [ требует наличия ] в качестве заключительного аргумента. Проверка этого потребовала бы минимальное количество кода, так зачем все же используются те самые ~1500 байтов?

Поскольку сложно просматривать отделенные исполнительные файлы, я создал собственную копию coreutils и сравнил список функций в каждом:

$ diff -u <(nm -S --defined-only src/[ | cut -d ' ' -f 2-) <(nm -S --defined-only src/test | cut -d ' ' -f 2-)--- /dev/fd/63      2021-02-02 20:21:35.337942508 -0800+++ /dev/fd/62      2021-02-02 20:21:35.341942491 -0800@@ -37,7 +37,6 @@ D __dso_handle d _DYNAMIC D _edata-0000000000000099 T emit_bug_reporting_address B _end 0000000000000004 D exit_failure 0000000000000008 b file_name@@ -63,7 +62,7 @@ 0000000000000022 T locale_charset 0000000000000014 T __lstat 0000000000000014 t lstat-0000000000000188 T main+00000000000000d1 T main 000000000000000b T make_timespec 0000000000000004 d nslots 0000000000000022 t one_argument@@ -142,16 +141,10 @@ 0000000000000032 T umaxtostr 0000000000000013 t unary_advance 00000000000004e5 t unary_operator-00000000000003d2 T usage+0000000000000428 T usage 0000000000000d2d T vasnprintf 0000000000000013 T verror 00000000000000ae T verror_at_line-0000000000000008 D Version-00000000000000ab T version_etc-0000000000000018 T version_etc_ar-000000000000042b T version_etc_arn-000000000000002f R version_etc_copyright-000000000000007a T version_etc_va 000000000000001c r wide_null_string.2840 0000000000000078 T x2nrealloc 000000000000000e T x2realloc

Главные участники это функции version_etc*. Что они делают?

Давайте посмотрим:

/* The three functions below display the --version information the   standard way [...]

Это 260 строк развернутых, интернационализированных, условных способов форматирования данных, которые составляют вывод --version. Все вместе они занимают около bc <<< "ibase=16; 7A+2F+42B+18+AB+8+99" = 1592 байтов.

Что это значит? Все просто. Дополнительные 4Кб уходят вот на что:

$ /usr/bin/[ --version[ (GNU coreutils) 8.30Copyright (C) 2018 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.Written by Kevin Braunsdorf and Matthew Bradburn.

[ --version недостает заключительной ], поэтому вызов оказывается недействительным, и результат определяется реализацией. GNU спокойно позволяет вывести информацию о версии.

Тем временем /usr/bin/test --version оказывается действительным вызовом, и POSIX предписывает, чтобы она возвращала успех, когда первый параметр (--version) является не пустой строкой.

Эта разница даже упоминается в документации:

Примечание: [ отвечает за опции --help и --version, а test нет.test рассматривает каждую из них просто как непустую строку.

Загадка разгадана!

(Задачка: каковы будут последствия, если вопреки POSIX test будет поддерживать --help и --version?)

Источник: habr.com
К списку статей
Опубликовано: 25.04.2021 16:15:44
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Блог компании ruvds.com

Настройка linux

Системное администрирование

*nix

Разработка под linux

Ruvds_перевод

Linux

Bash

Test

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru