[Настройка Linux, Системное администрирование, *nix, Разработка под Linux] Почему /usr/bin/test на 4Кб меньше, чем /usr/bin/[? (перевод)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Пользователь с 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 offset
15 .text 00006e82 0000000000002640 0000000000002640 00002640 2**4
16 .fini 0000000d 00000000000094c4 00000000000094c4 000094c4 2**2
17 .rodata 00001e4c 000000000000a000 000000000000a000 0000a000 2**5
А вот objdump -h /usr/bin/test:
15 .text 000068a2 0000000000002640 0000000000002640 00002640 2**4
16 .fini 0000000d 0000000000008ee4 0000000000008ee4 00008ee4 2**2
17 .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.30
Copyright (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
===========
===========
Автор оригинала: Vidar
===========Похожие новости:
- [Open source, Разработка под Linux] Разработчики Миннесотского университета опубликовали открытое письмо с извинениями сообществу Linux
- [Системное администрирование, Обработка изображений, Разработка под Linux] Генерация изображений с помощью echo/printf в 5 строчках кода без библиотек и заголовков (перевод)
- [Настройка Linux, Node.JS, Серверное администрирование, Go] Слабо поднять такой крошечный контейнер? Создаем контейнеризованный HTTP-сервер на 6kB (перевод)
- [Системное администрирование, IT-инфраструктура, Cisco, Сетевые технологии] Сброс пароля и базовая настройка Cisco 1941
- Команда из Университета Миннесоты пояснила мотивы экспериментов с сомнительными коммитами в ядро Linux
- [Python, Delphi, *nix, DevOps] Ansible-vault decrypt: обходимся без Ansible
- [Программирование, C, Компьютерное железо, DIY или Сделай сам] Не простые проблемы простого устройства — тачскрин
- [Производство и разработка электроники, Компьютерное железо, Ноутбуки] Энтузиасты собирают ноутбук на электронной бумаге. Выбираем дисплей и шасси
- [Системное администрирование, *nix, Разработка под Linux] Заметки о Unix: небольшая странность семейства вызовов exec*() (перевод)
- [Open source, Разработка под Linux] Линус Торвальдс прокомментировал бан Миннесотского университета сообществом разработчиков Linux
Теги для поиска: #_nastrojka_linux (Настройка Linux), #_sistemnoe_administrirovanie (Системное администрирование), #_*nix, #_razrabotka_pod_linux (Разработка под Linux), #_ruvds_perevod (ruvds_перевод), #_linux, #_bash, #_test, #_blog_kompanii_ruvds.com (
Блог компании RUVDS.com
), #_nastrojka_linux (
Настройка Linux
), #_sistemnoe_administrirovanie (
Системное администрирование
), #_*nix, #_razrabotka_pod_linux (
Разработка под Linux
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 15:34
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Пользователь с 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 offset
15 .text 00006e82 0000000000002640 0000000000002640 00002640 2**4 16 .fini 0000000d 00000000000094c4 00000000000094c4 000094c4 2**2 17 .rodata 00001e4c 000000000000a000 000000000000a000 0000a000 2**5 А вот objdump -h /usr/bin/test: 15 .text 000068a2 0000000000002640 0000000000002640 00002640 2**4
16 .fini 0000000d 0000000000008ee4 0000000000008ee4 00008ee4 2**2 17 .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.30 Copyright (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 =========== =========== Автор оригинала: Vidar ===========Похожие новости:
Блог компании RUVDS.com ), #_nastrojka_linux ( Настройка Linux ), #_sistemnoe_administrirovanie ( Системное администрирование ), #_*nix, #_razrabotka_pod_linux ( Разработка под Linux ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 15:34
Часовой пояс: UTC + 5