«awk» значение из нерегулярного вывода по имени столбца

gcc использует термины «архитектура» для обозначения «набора инструкций» конкретного ЦП, а «цель» охватывает комбинацию ЦП и архитектуры, а также другие переменные, такие как ABI, libc, endian-ness и другие (возможно, включая "голый металл"). Типичный компилятор имеет ограниченный набор целевых комбинаций (возможно, один ABI, одно семейство процессоров, но, возможно, и 32-, и 64-разрядные). Кросс-компилятор обычно означает компилятор с целью, отличной от системы, в которой он работает, или компилятор с несколькими целями или ABI (см. Также this ).

Переносимы ли двоичные файлы на разные архитектуры ЦП?

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

  • одна архитектура является надмножеством другой (обычно двоичные файлы x86 нацелены на i386 или i686, а не на последнюю и лучшую x86, например -march = core2 )
  • одна архитектура обеспечивает собственную эмуляцию или трансляцию другой (вы, возможно, слышали о Crusoe ) или предоставляет совместимые сопроцессоры (например, PS2 )
  • Поддержка ОС и среды выполнения , мультиархитектура (например,возможность запускать 32-разрядные двоичные файлы x86 на x86_64) или сделать виртуальную машину / JIT бесшовной (Android с использованием Dalvik или ART )
  • есть поддержка «толстых» двоичных файлов, которые по сути, содержат дублированный код для каждой поддерживаемой архитектуры

. Если вам каким-то образом удастся решить эту проблему, тогда возникнет другая переносимая двоичная проблема бесчисленных версий библиотеки (glibc, я смотрю на вас). (Большинство встроенных систем избавят вас, по крайней мере, от этой конкретной проблемы.)

Если вы еще этого не сделали, сейчас хорошее время для запуска gcc -dumpspecs и gcc --target-help , чтобы увидеть, с чем вы столкнетесь.

Жирные двоичные файлы имеют различные недостатки , но все же имеют потенциальное применение ( EFI ).

Однако в других ответах отсутствуют два дополнительных соображения: ELF и интерпретатор ELF, а также поддержка ядром Linux произвольных двоичных форматов . Я не буду вдаваться в подробности о двоичных файлах или байт-кодах для нереальных процессоров, хотя их можно рассматривать как «родные» и выполнять Java или скомпилированные двоичные файлы байт-кода Python , такие двоичные файлы не зависят от аппаратная архитектура (но зависит от соответствующей версии виртуальной машины, которая в конечном итоге запускает собственный двоичный файл).

Любая современная система Linux будет использовать двоичные файлы ELF (технические подробности в этом PDF ), в случае динамических двоичных файлов ELF ядро ​​отвечает за загрузку изображения в память, но это работа «Интерпретатор», установленный в заголовках ELF, выполняет тяжелую работу.Обычно это включает в себя обеспечение доступности всех зависимых динамических библиотек (с помощью раздела «Динамический», в котором перечислены библиотеки и некоторые другие структуры, в которых перечислены требуемые символы) - но это почти косвенный слой общего назначения.

$ file /bin/ls
/bin/ls: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses \
shared libs), stripped
$ readelf -p .interp /bin/ls
    String dump of section '.interp':
      [     0]  /lib/ld-linux.so.2

( /lib/ld-linux.so.2 также является двоичным файлом ELF, он не имеет интерпретатора и является собственным двоичным кодом.)

Проблема с ELF заключается в том, что заголовок в двоичном файле ( readelf -h / bin / ls ) отмечает его для конкретной архитектуры, класса (32- или 64-разрядный), порядка байтов и ABI (универсальный "толстые двоичные файлы вместо этого используют альтернативный двоичный формат Mach-O , который решает эту проблему, это возникло на NextSTEP). Это означает, что исполняемый файл ELF должен соответствовать системе, в которой он должен быть запущен. . Один аварийный люк - это интерпретатор, это может быть любой исполняемый файл (в том числе тот, который извлекает или отображает специфичные для архитектуры подразделы исходного двоичного файла и вызывает их), , но вы все еще ограничены Тип (ы) ELF, который ваша система позволит запускать. (Во FreeBSD есть интересный способ обработки файлов Linux ELF , его brandelf изменяет поле ELF ABI.)

Есть (с использованием binfmt_misc ) поддержки Mach-O в Linux , там есть пример, который показывает вам, как создать и запустить толстый (32- и 64-битный) двоичный файл. Форки ресурсов / ADS , как это было изначально сделано на Mac, могут быть обходным решением, но никакая собственная файловая система Linux не поддерживает это.

Более или менее то же самое относится к модулям ядра, .ko файлы также являются ELF (хотя у них нет набора интерпретаторов). В этом случае есть дополнительный уровень, который использует версию ядра ( uname -r ) в пути поиска, что теоретически можно было бы сделать вместо этого в ELF с управлением версиями, но я подозреваю, что с некоторой сложностью и небольшим выигрышем.

Как отмечалось в другом месте, Linux изначально не поддерживает толстые двоичные файлы, но есть активный проект жирного двоичного кода: FatELF .Он существует уже много лет , он никогда не был интегрирован в стандартное ядро ​​отчасти из-за проблем с патентом (срок действия которого истек). В настоящее время требуется поддержка как ядра, так и инструментальной цепочки. {{1} } Он не использует подход binfmt_misc , это устраняет проблемы с заголовком ELF и позволяет использовать расширенные модули ядра.

  1. Если у меня есть приложение, скомпилированное для работы на «цели x86, версия ОС Linux xyz», могу ли я просто запустить тот же скомпилированный двоичный файл в другой системе «цель ARM, версия ОС Linux xyz»?

Нет с ELF это не позволит вам сделать это.

  1. Если вышесказанное не соответствует действительности, единственный способ - заставить исходный код приложения перекомпилировать / перекомпилировать с помощью соответствующей инструментальной цепочки, например, arm-linux-gnueabi?

Простой ответ - да. (Сложные ответы включают эмуляцию, промежуточные представления, трансляторы и JIT; за исключением случая «понижения» двоичного кода i686 для использования только кодов операций i386, они, вероятно, здесь не интересны, а исправления ABI потенциально так же

  1. Точно так же, если у меня есть загружаемый модуль ядра (драйвер устройства), который работает на «цель x86, версия ОС Linux xyz», могу ли я просто загрузить / использовать тот же скомпилированный .ko на другая система 'ARM target, linux OS version xyz'?

Нет, ELF не позволит вам это сделать.

  1. Если вышесказанное неверно, единственный способ - заставить исходный код драйвера перекомпилировать / перекомпилировать с помощью соответствующей инструментальной цепочки, например, arm-linux-gnueabi?

Простой ответ - да. Я считаю, что FatELF позволяет построить .ko , который является многоархитектурным, но в какой-то момент необходимо создать двоичную версию для каждой поддерживаемой архитектуры. Вещи, для которых требуются модули ядра, часто идут с исходным кодом и собираются по мере необходимости, например VirtualBox делает это.

Это уже длинный бессвязный ответ, остался только один обходной путь. Ядро уже имеет встроенную виртуальную машину, хотя и выделенную: виртуальная машина BPF , которая используется для сопоставления пакетов. Удобочитаемый фильтр «host foo, а не порт 22») компилируется в байт-код, и фильтр пакетов ядра выполняет его . Новый eBPF предназначен не только для пакетов, теоретически код виртуальной машины переносится на любой современный Linux, и llvm поддерживает его , но по соображениям безопасности он, вероятно, не будет подходить ни для чего. кроме административных правил.


Теперь, в зависимости от того, насколько вы щедры с определением двоичного исполняемого файла, вы можете (ab) использовать binfmt_misc для реализации толстой двоичной поддержки с помощью сценария оболочки и файлов ZIP в качестве формата контейнера:

#!/bin/bash

name=$1
prog=${1/*\//}      # basename
prog=${prog/.woz/}  # remove extension
root=/mnt/tmpfs
root=$(TMPDIR= mktemp -d -p ${root} woz.XXXXXX)
shift               # drop argv[0], keep other args

arch=$(uname -m)                  # i686
uname_s=$(uname -s)               # Linux
glibc=$(getconf GNU_LIBC_VERSION) # glibc 2.17
glibc=${glibc// /-}               # s/ /-/g

# test that "foo.woz" can unzip, and test "foo" is executable
unzip -tqq "$1" && {
  unzip -q -o -j -d ${root} "$1"  "${arch}/${uname_s}/${glibc}/*" 
  test -x ${root}/$prog && ( 
    export LD_LIBRARY_PATH="${root}:${LD_LIBRARY_PATH}"
    #readlink -f "${root}/${prog}"   # for the curious
    exec -a "${name}" "${root}/${prog}" "$@" 
  )
  rc=$?
  #rm -rf -- "${root}/${prog}"       # for the brave
  exit $rc
}

Назовите этот «wozbin» и настройте его примерно так:

mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
printf ":%s:%s:%s:%s:%s:%s:%s" \
  "woz" "E" "" "woz" "" "/path/to/wozbin" ""  > /proc/sys/fs/binfmt_misc/register

Это регистрирует файлы .woz в ядре, вместо этого запускается сценарий wozbin с его первым в качестве аргумента указан путь к вызванному файлу .woz .

Чтобы получить переносимый (толстый) файл .woz , просто создайте тест .woz ZIP-файл с иерархией каталогов таким образом:

i686/ 
    \- Linux/
            \- glibc-2.12/
armv6l/
    \- Linux/
            \- glibc-2.17/

В каждом каталоге arch / OS / libc (произвольный выбор) поместите архитектурно-зависимый тестовый двоичный файл и такие компоненты, как .so файлов. Когда вы вызываете его, необходимый подкаталог извлекается в файловую систему в памяти tmpfs (здесь / mnt / tmpfs ) и вызывается.

3
03.03.2017, 14:37
2 ответа

Имя столбца для поиска предоставляется через -col = в командной строке, как показано.

Код ищет указанное имя столбца, которое начинается либо с начала строки, либо с пробела, и отмечается размер до начала следующего столбца или конца строки.

Вооружившись этой информацией, мы ждем до eof и извлекаем подстроку из последней строки.

helm history release | perl -slne '$. == 1 and /(?:(?<=^)|(?<=\s))\Q$col\E(?:\s*|$)/ and ($p,$l)=($-[0],$+[0]-$-[0]); eof and print substr($_, $p, $l) =~ s/\s*$//r;' -- -col='REVISION' 
'
1
27.01.2020, 21:30
col='REVISION' \
   perl -lne '
       $. == 1 and /(?:^|\s)(?=$ENV{col}(?:\s|$))/g and $h=pos, next;
       /^.{$h}/g; /\G(\S+)/ and print $1;
       next;
   ' yourfile


col='REVISION' \
   perl -lne '
      $. == 1 and $h = index($_, $ENV{col}), next;
      /^.{$h}/g; /\G(\S+)/ and print $1;
   ' yourfile

В первой строке мы вычисляем позицию REVISION , используя index () , работающий с текущей строкой $ _ . Для всех оставшихся строк мы пропускаем позиции посредством сопоставления /^.../g. Затем используйте привязку \ G , чтобы начать сопоставление с того места, где мы остановились ранее, и возьмите лежащие вне пробела символы \ S + .

0
27.01.2020, 21:30

Теги

Похожие вопросы