LLVM 도구를 사용하여 바이너리 데이터를 실행 파일에 포함

LLVM 도구를 사용하여 바이너리 데이터를 실행 파일에 포함

과거에는 .o먼저 GNU 링커를 사용하여 리소스 파일(이미지)을 파일로 변환하여 프로그램에 포함시켰습니다. 예를 들어:

ld -r -b binary -o file.o file.svg

FreeBSD 12부터 기본 링커가 GNU에서 LLVM으로 변경되었습니다. 링커가 명령줄 옵션을 이해하는 것처럼 보이지만 이로 인해 오류가 발생합니다. 예를 들어:

ld -r -b binary -o file.o file.svg
ld: error: target emulation unknown: -m or at least one .o file required

또한 명령줄 옵션을 사용해 보았습니다.ld.lld(1)매뉴얼 페이지:

ld --relocatable --format=binary -o file.o file.svg
ld: error: target emulation unknown: -m or at least one .o file required

나는 올바른 도구를 사용하고 있는가? -m이 옵션에 대한 값을 지정 해야 합니까 ?

답변1

추가해야 할 것 같습니다 -z noexecstack(ELF 바이너리에도 추가됨).LLD 7.0.0). 기본적으로 취약한 실행 가능한 스택 영역이 있습니다.스택 메모리를 통한 활용. 귀하의 바이너리 이미지에는 실행 가능한 스택이 없으므로 이것이 실패하는 이유라고 생각합니다. 이 오류는 사용할 대상 모의 대상(사용하지 않는 대상)을 스택에 알려야 하기 때문에 혼란스럽습니다.

데이비드 허먼모든 노력을 다해 다음을 포함하는 크로스 플랫폼 솔루션을 찾았습니다.

  • GNU-ld
  • GNU-골드
  • GNU 라이브러리 도구
  • 크로스 컴파일 사용
  • LLVM 사용
  • 외부 비표준 도구가 필요하지 않습니다.

마법의 호출은 다음과 같습니다:

$(LD) -r -o "src/mydata.bin.o" -z noexecstack --format=binary "src/mydata.bin"

대부분의 경우 이 바이너리 세그먼트를 읽기 전용으로 설정하려고 합니다.

$(OBJCOPY) --rename-section .data=.rodata,alloc,load,readonly,data,contents "src/mydata.bin.o"

고쳐 쓰다:

내 시스템이 다음과 같기 때문에 테스트할 수 없습니다.

$ uname -r
11.2-STABLE
$ ld -V
GNU ld 2.17.50 [FreeBSD] 2007-07-03
  Supported emulations:
   elf_x86_64_fbsd
   elf_i386_fbsd

이것을 테스트하기 위해 FreeBSD 12.0으로 가상 머신을 시작했고 다음을 발견했습니다:

$ uname -r
12.0-RELEASE
$ ld -V
LLD 6.0.1 (FreeBSD 335540-1200005) (compatible with GNU linkers)

7.0.0에만 추가되었으며 -z noexecstack목록에는 표시되지 않습니다.매뉴얼 페이지6.0.1의 경우. 더욱 짜증나는 점은 지원되지 않는 값을 지정해도 -z오류가 발생하지 않는다는 것입니다!

이것이 작동하는지 테스트하기 위해 LLVM 7로 업그레이드하지 않았습니다. @Richard Smith는 -m다른 답변에 조롱을 지정하여 올바른 솔루션을 직접 찾았습니다. LLD가 지원하는 에뮬레이션을 나열하면 -V이 경로가 훨씬 쉬울 것입니다 .

file이 명령을 사용하면 file.oSYSV ELF로 식별되는 것을 볼 수 있습니다. 이것으로 충분할 수 있습니다. 그러나 시스템과 정확히 동일하려면 다음을 elf_amd64_fbsd사용하십시오 .별명을 위한 elf_x86_64_fbsd. 짜증나게 ld -V도 GNU ld처럼 지원되는 LLD 에뮬레이션을 출력하지 않습니다.

$ file /bin/cat
/bin/cat: ELF 64-bit LSB executable, x86-64, version 1 (FreeBSD), dynamically linked, interpreter /libexec/ld-elf.so.1, for FreeBSD 12.0 (1200086), FreeBSD-style, stripped
$ ld -r -b binary -m elf_amd64 -o data.o data.bin
$ file data.o
data.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
$ ld -r -b binary -m elf_amd64_fbsd -o data.o data.bin
$ file data.o
data.o: ELF 64-bit LSB relocatable, x86-64, version 1 (FreeBSD), not stripped

elf_amd64_fbsdelf_x86_64_fbsd(참조D7837그리고D24356). LLD가 -V출력 에 에뮬레이션을 추가하길 바랍니다 .

답변2

소스코드를 확인해 보니 맞는 내용이더군요타겟 시뮬레이션내 플랫폼은elf_amd64. 따라서 이진 파일에서 개체 파일로의 변환은 다음을 사용하여 수행할 수 있습니다.

ld -r -b binary -m elf_amd64 -o file.o file.svg

답변3

정말 수고할 가치가 있나요? 이것은 애초에 이식성이 없습니다.

.svg를 C char 배열 예로 변환하는 것이 좋습니다.

$ cat Makefile
.SUFFIXES: .svg
.svg.c:
        od -tx1 $< | sed 's/ /,0x/g;s/[^,]*//;1s/,/char $*[]={/;$$s/$$/};/' > $@

$ make file.o
od -tx1 file.svg | sed 's/ /,0x/g;s/[^,]*//;1s/,/char file[]={/;$s/$/};/' > file.c
cc    -c -o file.o file.c
rm file.c

물론 배열 이름을 다른/보다 강력한 이름으로 설정할 수 있습니다(예: GNU make를 사용하는 char $(subst /,_,$*)[] = ...대신 ). 또는 끔찍한 od+sed 조합 대신 char $*[] = ...C로 작성된 임시 변환기를 구축할 수도 있습니다 .bin2c

답변4

나는 다음과 같은 간단한 도구를 제공하고 싶습니다.리소스 임베딩. 범위는 비슷하지만 LLVM을 기반으로 하지 않습니다. 기본적으로 NASM이나 Gas를 사용하여 어셈블리 파일을 통해 바이너리를 포함합니다. 이는 고급 CMake 인터페이스로 래핑됩니다.

add_executable(res_example "example.cpp")
res_embed(TARGET res_example NAME "my_cool_image" PATH ${CMAKE_CURRENT_SOURCE_DIR}/file.svg)

그런 다음 프로그램에 포함된 리소스를 다음과 같이 사용할 수 있습니다.

#include "res_embed.h"

#include <cstdio>

int main(int argc, char* argv[])
{
    printf("%s", res::embed::get("my_cool_image"));
    return 0;
}

대부분의 플랫폼에서 가스를 사용할 수 있는 경우 솔루션은 이식 가능합니다. 또한 NASM을 통해 Windows에서 MSVC를 지원합니다. 이는 다음과 같은 점에서 LLD 접근 방식과 유사합니다. res_embed는 리소스를 C 배열로 포함하려고 시도한 결과를 방지합니다. 이는 명백한 이유 없이 많은 수의 리소스가 나타날 경우 컴파일 속도가 크게 느려질 수 있습니다.

관련 정보