바이너리는 다른 CPU 아키텍처에서 이식 가능합니까?


16

저의 목표는 임베디드 리눅스를 위해 개발할 수 있도록하는 것입니다. ARM을 사용하는 베어 메탈 임베디드 시스템에 대한 경험이 있습니다.

다른 CPU 대상을 개발하는 데 대한 일반적인 질문이 있습니다. 내 질문은 다음과 같습니다.

  1. ' x86 대상, Linux OS 버전 xyz '에서 실행되도록 컴파일 된 응용 프로그램이있는 경우 다른 시스템 ' ARM target, linux OS version xyz ' 에서 동일한 컴파일 된 바이너리를 실행할 수 있습니까?

  2. 위의 내용이 사실이 아닌 경우, 유일한 방법은 관련 툴체인 '예 : arm-linux-gnueabi'를 사용하여 애플리케이션 소스 코드를 재 빌드 / 재 컴파일하는 것입니까?

  3. 마찬가지로 ' x86 대상, Linux OS 버전 xyz '에서 작동하는로드 가능한 커널 모듈 (장치 드라이버)이 있는 경우 다른 시스템 ' ARM 대상, Linux OS 버전 xyz ' 에서 동일한 컴파일 된 .ko를로드 / 사용할 수 있습니까 ? ?

  4. 위의 내용이 사실이 아닌 경우 유일한 방법은 관련 툴체인 '예 : arm-linux-gnueabi'를 사용하여 드라이버 소스 코드를 다시 빌드 / 재 컴파일하는 것입니까?


27
아니요, 예, 아니요
hobbs

7
AMD 타겟과 인텔 타겟이 없으며 둘 다에 대한 단일 x86 타겟 만 있음을 인식하는 데 도움이됩니다. 인텔과 AMD가 충분히 호환되기 때문입니다. 그런 다음 ARM 타겟이 특정 이유로, 즉 ARM CPU가 Intel / AMD / x86과 호환되지 않기 때문에 존재한다는 것이 분명해졌습니다.
MSalters

1
Java 런타임과 같은 이식 가능한 런타임 환경에서 실행되도록 설계된 바이트 코드가 아닌 한 아닙니다. 임베디드 용으로 코드를 작성하는 경우 코드는 낮은 수준의 프로세서 별 최적화 또는 기능에 의존 할 가능성이 높으며 이식이 매우 어려워 대상 플랫폼에 대한 컴파일 이상의 작업이 필요합니다 (예 : 어셈블리 코드 변경, 재 작성 가능) 여러 모듈 또는 전체 프로그램).
bwDraco

1
@MSalters : 실제로, 우리는 AMD 대상을 가지고 있습니다 : amd64는 종종 x86-64로 표시됩니다 (x86은 일반적으로 i386으로 다시 표시됩니다). 다행히도 인텔은 64 비트 x86이 amd64 바이너리를 실행할 수 있도록 AMD 아키텍처를 복사 한 후 확장했습니다.
slebetman

답변:


42

아니요. 바이너리는 대상 아키텍처에 맞게 (재) 컴파일되어야하며 Linux는 기본적으로 팻 바이너리 와 같은 것을 제공하지 않습니다 . 그 이유는 코드가 특정 아키텍처에 대한 머신 코드로 컴파일되고 머신 코드가 대부분의 프로세서 제품군마다 매우 다르기 때문입니다 (예 : ARM과 x86은 매우 다름).

편집 : 일부 아키텍처는 이전 버전과의 호환성을 제공하며 다른 아키텍처와의 호환성은 매우 드 that니다. 64 비트 CPU에서는 32 비트 버전과 호환되는 것이 일반적입니다 (그러나 정적으로 링크 하지 않는 한 종속 라이브러리도 C 표준 라이브러리를 포함하여 32 비트 여야 함 ). 또한 Itanium 도 언급 할 가치 가 있습니다. 여기서 Itanium 은 매우 느리지 만 x86 코드 (32 비트 만 해당)를 실행할 수 있습니다. x86 코드의 느린 실행 속도는 시장에서 그다지 성공적이지 않은 이유의 일부였습니다.

호환성 모드에서도 이전 CPU의 최신 명령어로 컴파일 된 이진 파일은 계속 사용할 수 없습니다 (예 : Nehalem x86 프로세서 의 32 비트 이진 파일에서는 AVX를 사용할 수 없습니다 . CPU는이를 지원하지 않습니다).

커널 모듈은 관련 아키텍처를 위해 컴파일되어야합니다. 또한 32 비트 커널 모듈은 64 비트 커널에서 작동하지 않으며 그 반대도 마찬가지입니다.

교차 컴파일 바이너리에 대한 정보 (따라서 타겟 ARM 디바이스에 툴체인이 필요하지 않음)는 아래 grochmal의 포괄적 인 답변을 참조하십시오.


1
일부 x86 바이너리가 x64 플랫폼에서 실행될 수 있다는 점을 감안할 때 x86과 x64 간의 호환성 (또는 부족)에 대해 설명 할 가치가 있습니다. (이것은 Linux에서는 확실하지 않지만 Windows에서는 예입니다.)
jpmc26

4
@ jpmc26 리눅스에서 가능하다; 그러나 호환성 라이브러리를 먼저 설치해야 할 수도 있습니다. x86 지원은 Win64 설치의 비 선택적 부분입니다. Linux에서는 선택 사항입니다. 그리고 Linux 세계는 64 비트 버전의 모든 것을 사용할 수 있도록하기 때문에 일부 배포판에는 기본적으로 32 비트 라이브러리가 모두 설치되어 있지 않습니다. (얼마나 일반적인지 잘 모르겠지만 이전에 주류 배포판을 실행하는 사람들로부터 그것에 대해 몇 가지 질문을 보았습니다.)
Dan은 Firelight에 의해 조사 중입니다.

@ jpmc26 노트로 답변을 업데이트했습니다. 나는 그것을 언급하는 것에 대해 생각했지만 대답을 복잡하게하고 싶지 않았습니다.
Elizafox

16

Elizabeth Myers는 정확하며 각 아키텍처에는 해당 아키텍처에 대해 컴파일 된 바이너리가 필요합니다. 시스템이 실행되는 것과 다른 아키텍처에 대한 바이너리를 빌드하려면 cross-compiler.


대부분의 경우 크로스 컴파일러를 컴파일해야합니다. 나는 경험이있다 gcc(그러나 llvm다른 컴파일러는 비슷한 매개 변수를 가지고 있다고 생각한다 ). gcc크로스 컴파일러를 추가하여 달성 --target구성에 :

./configure --build=i686-arch-linux-gnu --target=arm-none-linux-gnueabi

당신은 컴파일 할 필요가 gcc, glibc그리고 binutils이러한 매개 변수 (및 대상 시스템에서 커널의 커널 헤더를 제공한다).

실제로 이것은 훨씬 더 복잡하고 다른 시스템에서 다른 빌드 오류가 발생합니다.

GNU 툴체인을 컴파일하는 방법에 대한 몇 가지 안내서가 있지만 Linux From Scratch를 권장합니다. Linux From Scratch 는 지속적으로 유지 관리되며 제시된 명령의 기능을 설명하는 데 매우 효과적입니다.

또 다른 옵션은 크로스 컴파일러의 부트 스트랩 컴파일입니다. 크로스 컴파일러를 다른 아키텍처의 다른 아키텍처 crosstool-ng로 컴파일하는 데 어려움을 겪었 습니다. 크로스 컴파일러를 빌드하는 데 필요한 툴체인에 부트 스트랩을 제공합니다.

crosstool-ng다른 아키텍처에서 여러 대상 삼중 소켓 을 지원합니다 . 기본적으로 사람들은 크로스 컴파일러 도구 체인을 컴파일하는 동안 발생하는 문제를 해결하기 위해 시간을 할애하는 부트 스트랩입니다.


여러 배포판에서 크로스 컴파일러를 패키지로 제공합니다.

다시 말해, 크로스 컴파일러 측면에서 사용 가능한 배포판을 확인하십시오. 배포판에 필요에 맞는 크로스 컴파일러가없는 경우 언제든지 직접 컴파일 할 수 있습니다.

참고 문헌 :


커널 모듈 참고

크로스 컴파일러를 직접 컴파일하는 경우 커널 모듈을 컴파일하는 데 필요한 모든 것이 있습니다. 컴파일하려면 커널 헤더가 필요하기 때문 glibc입니다.

그러나 배포판에서 제공하는 크로스 컴파일러를 사용하는 경우 대상 시스템에서 실행되는 커널의 커널 헤더가 필요합니다.


FWIW Fedora에는 크로스 컴파일러도 포함되어 있습니다.
mattdm

@ mattdm-고마워, 답변이 조정되었습니다. 페도라 위키의 올바른 부분이 연결되어 있다고 생각합니다.
grochmal

2
Scratch에서 Linux보다 쉬운 방법 다른 아키텍처를위한 Linux 및 툴체인을 얻는 방법은 다음과 같습니다 crosstool-ng. 목록에 추가하고 싶을 수도 있습니다. 또한 주어진 아키텍처에 대해 GNU 크로스 툴체인을 수동으로 구성하고 컴파일하는 것은 --target플래그 보다 훨씬 복잡하고 지루 합니다. LLVM이 인기를 얻고있는 이유 중 하나라고 생각합니다. 다른 아키텍처를 대상으로하기 위해 재 구축 할 필요가 없도록 설계되었습니다. 대신 동일한 프론트 엔드 및 최적화 라이브러리를 사용하여 여러 백엔드를 대상으로 지정할 수 있습니다.
Iwillnotexist Idonotexist

@IwillnotexistIdonotexist-감사합니다. 답변을 더 조정했습니다. 나는 전에 crosstool-ng에 대해 들어 본 적이 없으며 매우 유용합니다. 귀하의 의견은 실제로 매우 유용했습니다.
grochmal

9

(소스 코드가없는 즉,) 최후의 수단으로, 당신이 좋아하는 에뮬레이터를 사용하여 다른 아키텍처에서 바이너리를 실행할 수 있습니다 qemu, dosbox또는 exagear. 일부 에뮬레이터는 Linux 이외의 시스템을 에뮬레이션하도록 설계되었습니다 (예 : dosboxMS-DOS 프로그램을 실행하도록 설계되었으며 널리 사용되는 게임 콘솔 용 에뮬레이터가 많이 있습니다). 에뮬레이션은 성능 오버 헤드가 현저합니다. 에뮬레이트 된 프로그램은 기본 프로그램보다 2-10 배 느립니다.

네이티브가 아닌 CPU에서 커널 모듈을 실행해야하는 경우 동일한 아키텍처의 커널을 포함하여 전체 OS를 에뮬레이션해야합니다. AFAIK Linux 커널 내에서 외부 코드를 실행할 수 없습니다.


3
에뮬레이션에 대한 속도 불이익은 종종 10 배 이상이지만 4GHz 시스템 (250 : 1 속도 차이)에서 16Mhz 시스템 용으로 작성된 코드를 실행하려고하면 50 : 1 속도 불이익이있는 에뮬레이터가 여전히 원래 플랫폼에서 실행했던 것보다 훨씬 빠르게 코드를 실행하십시오.
supercat

7

바이너리는 x86과 ARM간에 이식 가능하지 않을뿐만 아니라 ARM의 다양한 특징이 있습니다.

실제로 발생할 수있는 것은 ARMv6과 ARMv7입니다. 라즈베리 파이 1은 ARMv6이고 이후 버전은 ARMv7입니다. 따라서 Pi 1에서 작동하지 않는 후자의 코드를 컴파일 할 수 있습니다.

다행스럽게도 오픈 소스와 자유 소프트웨어의 이점 중 하나는 소스를 가지고있어 어떤 아키텍처에서든이를 다시 빌드 할 수 있다는 것입니다. 이것은 약간의 작업이 필요할 수 있습니다.

(ARM 버전 관리는 혼란 스럽지만 숫자 앞에 V가 있으면 명령어 세트 아키텍처 (ISA)에 대해 이야기하고 있습니다. 그렇지 않으면 "Cortex M0"또는 "ARM926EJS"와 같은 모델 번호입니다. ISA 번호와 관련이 있습니다.)


2
... 그리고 동일한 ARM 풍미에 대해 다른 하위 풍미가 있으며 동일한 하드웨어에 대해 다른 ABI도 있습니다 (전체 ARM soft / softfp / hard floating point mess에 대해 생각하고 있습니다).
Matteo Italia

1
@MatteoItalia Ugh. 여러 개의 ABI는 snafu였으며 질병보다 더 나쁜 치료법이었습니다. 일부 ARM에는 VFP 또는 NEON 레지스터가 전혀 없었고 일부는 16 개, 32 개가있었습니다. Cortex-A8 및 이전 버전에서 NEON 엔진은 나머지 코어 뒤에 12 개의 CC를 실행하여 벡터 출력을 GPR 비용으로 전송했습니다. 제비. ARM은 많은 기능을 공통으로 사용하여 올바른 작업을 수행했습니다.
Iwillnotexist Idonotexist

7

당신은 항상 목표로해야 할 플랫폼을. 가장 간단한 경우, 대상 CPU는 바이너리로 컴파일 된 코드를 직접 실행합니다 (이것은 대략 MS DOS의 COM 실행 파일에 해당합니다). 제가 방금 발명 한 두 가지 플랫폼 인 Armistice과 Intellio를 고려해 봅시다. 두 경우 모두 화면에 42를 출력하는 간단한 hello world 프로그램이 있습니다. 또한 플랫폼과 무관하게 다중 플랫폼 언어를 사용한다고 가정하므로 소스 코드는 모두 동일합니다.

Print(42)

Armistice에는 숫자를 인쇄하는 간단한 장치 드라이버가 있으므로 포트로 출력하기 만하면됩니다. 이식 가능한 어셈블리 언어에서 이것은 다음과 같습니다.

out 1234h, 42

그러나 Intellio 시스템에는 그러한 것이 없으므로 다른 계층을 거쳐야합니다.

mov a, 10h
mov c, 42
int 13h

죄송합니다. 기계 코드를 만들기 전에 이미 둘 사이에 차이가 있습니다. 이것은 Linux와 MS DOS 또는 IBM PC와 X-Box의 차이점과 거의 일치합니다 (둘 다 동일한 CPU를 사용하더라도).

그러나 이것이 OS를위한 것입니다. 응용 프로그램 계층에서 서로 다른 모든 하드웨어 구성이 동일한 방식으로 처리되도록하는 HAL이 있다고 가정 해 봅시다. 기본적으로 Armistice에서도 Intellio 방식을 사용하며 "휴대용 어셈블리"코드는 동일합니다. 이것은 현대 유닉스 계열 시스템과 Windows 모두에서 사용되며 종종 임베디드 시나리오에서도 사용됩니다. 좋습니다. 이제 Armistice과 Intellio에서 모두 동일한 휴대용 어셈블리 코드를 사용할 수 있습니다. 그러나 바이너리는 어떻습니까?

우리가 가정했듯이 CPU는 바이너리를 직접 실행해야합니다. mov a, 10hIntellio에서 코드의 첫 번째 줄을 살펴 보겠습니다 .

20 10

오. 밝혀이 mov a, constant자신의 연산 코드와 함께, 그것은 자신의 명령이 인기입니다. 휴전은 이것을 어떻게 처리합니까?

36 01 00 10

흠. 에 대한 opcode가 mov.reg.imm있으므로 할당하려는 레지스터를 선택하려면 다른 인수가 필요합니다. 상수는 항상 빅 엔디안 표기법으로 2 바이트 단어입니다. Armistice은 실제로 Armistice의 모든 명령어의 길이가 4 바이트이며 예외는 없습니다.

이제 Armistice에서 Intellio의 바이너리를 실행한다고 상상해보십시오. CPU가 명령어 디코딩을 시작하고 opcode를 찾습니다 20h. 휴전에서 이것은 and.imm.reg지시에 해당한다. 2 바이트 워드 상수 ( 10XX이미 읽기 ) 를 읽은 다음 레지스터 번호 (또 다른 XX) 를 읽으려고합니다 . 잘못된 인수로 잘못된 명령을 실행하고 있습니다. 더 나쁜 것은, 다음 명령어는 완전한 가짜 일 것입니다. 왜냐하면 우리는 실제로 다른 명령어를 먹었으므로 데이터라고 생각했기 때문입니다.

이 응용 프로그램은 작동 할 가능성이 없으며 거의 ​​즉시 중단되거나 중단됩니다.

그렇다고해서 실행 파일이 항상 Intellio 또는 Armistice에서 실행되고 있다고 말할 필요는 없습니다. CPU와는 독립적 인 플랫폼 (예 : bashUnix 와 같음 ) 또는 CPU와 OS (Java 또는 .NET과 같으며 현재는 JavaScript) 와 같은 플랫폼 만 정의하면됩니다 . 이 경우 응용 프로그램은 모든 다른 CPU 및 OS에 대해 하나의 실행 파일을 사용할 수 있지만 대상 시스템에는 플랫폼 독립적 코드를 CPU는 실제로 실행할 수 있습니다. 성능, 비용 또는 기능에 영향을 줄 수 있습니다.

CPU는 일반적으로 제품군으로 제공됩니다. 예를 들어, x86 제품군의 모든 CPU에는 정확히 동일한 방식으로 인코딩 된 공통 명령어 세트가 있으므로 모든 x86 CPU는 확장을 사용하지 않는 한 모든 x86 프로그램을 실행할 수 있습니다 (예 : 부동 소수점 연산 또는 벡터 연산). x86에서 오늘날 가장 일반적인 예는 인텔과 AMD입니다. Atmel은 ARM 제품군에서 CPU를 설계하는 잘 알려진 회사로 임베디드 장치에 널리 사용됩니다. 예를 들어 애플은 자체 ARM CPU를 가지고있다.

그러나 ARM은 x86과 완전히 호환되지 않습니다. 설계 요구 사항이 매우 다르고 공통점이 거의 없습니다. 명령어는 완전히 다른 opcode를 가지며, 다른 방식으로 디코딩되며, 메모리 주소가 다르게 처리됩니다. 안전한 작업을 통해 x86 CPU와 ARM CPU에서 실행되는 이진 파일을 만들 수 있습니다. 두 가지를 구별하고 완전히 다른 두 가지 명령어로 점프하지만 여전히 런타임에 올바른 세트를 선택하는 부트 스트 래퍼와 함께 두 버전에 대한 별도의 명령어가 있음을 의미합니다.


3

이 질문을보다 친숙한 환경으로 다시 캐스팅 할 수 있습니다. 유추하여 :

"루비 프로그램을 실행하고 싶지만 플랫폼에 파이썬 인터프리터 만 있습니다. 파이썬 인터프리터를 사용하여 루비 프로그램을 실행할 수 있습니까, 아니면 파이썬에서 프로그램을 다시 작성해야합니까?"

명령어 세트 아키텍처 ( "대상")는 언어 ( "기계 언어")이며 다른 CPU는 다른 언어를 구현합니다. 따라서 ARM 바이너리에 Intel 바이너리를 실행하도록 요청하는 것은 Python 인터프리터를 사용하여 Ruby 프로그램을 실행하는 것과 매우 유사합니다.


2

gcc는``아키텍처 ''라는 용어를 사용하여 특정 CPU의``명령 세트 ''를 의미하고 "target"은 CPU와 아키텍처의 조합 및 ABI, libc, 엔디안 등의 다른 변수를 포함합니다. ( "베어 메탈"포함). 일반적인 컴파일러에는 제한된 대상 조합 세트 (아마도 하나의 ABI, 하나의 CPU 제품군, 그러나 32 비트 및 64 비트 둘 다)가 있습니다. 크로스 컴파일러는 일반적으로 실행되는 시스템 이외의 대상이있는 컴파일러 또는 여러 개의 대상 또는 ABI가있는 컴파일러를 의미합니다 ( this 참조 ).

바이너리는 다른 CPU 아키텍처에서 이식 가능합니까?

일반적으로 아닙니다. 일반적인 용어로 바이너리 는 특정 CPU 또는 CPU 제품군에 대한 기본 객체 코드 입니다. 그러나 적당히 휴대 성이 높을 수있는 몇 가지 경우가 있습니다.

  • 한 아키텍처는 다른 아키텍처의 상위 집합입니다 (일반적으로 x86 바이너리는 최신 및 가장 큰 x86 대신 i386 또는 i686을 대상으로합니다 -march=core2)
  • 한 아키텍처는 다른 아키텍처의 네이티브 에뮬레이션 또는 번역을 제공하거나 ( Crusoe에 대해 들어봤을 수도 있음 ) 호환 가능한 보조 프로세서 (예 : PS2 )를 제공합니다.
  • OS 및 런타임은 다중 아키텍처 (예 : x86_64에서 32 비트 x86 바이너리를 실행하는 기능)를 지원 하거나 VM / JIT를 원활하게 만듭니다 ( Dalvik 또는 ART를 사용하는 Android )
  • 지원되는 각 아키텍처에 대해 본질적으로 중복 코드를 포함하는 "지방"바이너리에 대한 지원이 있습니다.

어떻게 든이 문제를 해결하면 무수한 라이브러리 버전 의 다른 휴대용 바이너리 문제 (당신을보고있는 glibc)가 나타납니다. (대부분의 임베디드 시스템은 적어도 특정 문제로부터 당신을 구할 수 있습니다.)

당신이 이미하지 않은 경우, 지금 실행하는 것이 시간 gcc -dumpspecsgcc --target-help당신에 대해 뭘하는지 볼 수는.

팻 바이너리는 여러 가지 단점 이 있지만 여전히 잠재적 인 용도 ( EFI )를 가지고 있습니다.

그러나 ELF와 ELF 인터프리터 및 임의의 이진 형식에 대한 Linux 커널 지원이라는 두 가지 추가 고려 사항이 다른 답변에서 누락되었습니다 . 여기서는 실제 프로세서가 아닌 프로세서의 바이너리 또는 바이트 코드에 대해서는 자세하게 설명하지 않겠지 만,이를 "네이티브"로 취급하고 Java 또는 컴파일 된 파이썬 바이트 코드 바이너리를 실행할 수 있지만 이러한 바이너리는 하드웨어 아키텍처와 무관합니다. 관련 VM 버전에서 궁극적으로 기본 바이너리를 실행합니다).

현대의 모든 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 (Apple의 "범용"지방 바이너리는 대체 바이너리 형식 Mach-O를 사용함)로 표시한다는 것입니다 대신이 문제를 해결하는 것은 NextSTEP에서 시작되었습니다). 이는 ELF 실행 파일이 실행될 시스템과 일치해야한다는 것을 의미합니다. 하나의 이스케이프 해치는 인터프리터입니다. 이것은 모든 실행 파일 (원래 이진의 아키텍처 특정 하위 섹션을 추출 또는 매핑하고 호출하는 것을 포함) 일 수 있지만 여전히 시스템에서 실행할 수있는 ELF의 유형에 의해 제약을받습니다. . (FreeBSD는 흥미로운 방법이 리눅스 ELF 파일 처리 , 그 brandelf수정합니다 ELF ABI 필드를.)

Linux 에서 Mach-O에 대한 (사용 binfmt_misc) 지원이 있으며, 지방 (32 및 64 비트) 바이너리를 생성하고 실행하는 방법을 보여주는 예가 있습니다. 원래 Mac에서 수행 된 리소스 포크 / ADS 는 해결 방법이 될 수 있지만 기본 Linux 파일 시스템에서는이를 지원하지 않습니다.

커널 모듈에도 거의 같은 내용이 적용되며 .ko파일도 ELF (인터프리터 세트는 없지만)입니다. 이 경우 uname -r검색 경로에 커널 버전 ( ) 을 사용하는 추가 계층이 있습니다. 이는 ELF에서 버전 관리를 통해 대신 이론적으로 수행 할 수 있지만 다소 복잡하고 약간의 이득이 있습니다.

다른 곳에서 언급했듯이 Linux는 기본적으로 지방 바이너리를 지원하지 않지만 FatELF 라는 활성 지방 바이너리 프로젝트가 있습니다. 그것은 수년 전부터 있었고 (현재 만료 된) 특허 문제로 인해 표준 커널에 부분적으로 통합되지 않았습니다. 현재는 커널 및 툴체인 지원이 모두 필요합니다. binfmt_misc접근 방식을 사용하지 않으므로 ELF 헤더 문제를 회피하고 뚱뚱한 커널 모듈도 허용합니다.

  1. 'x86 대상, Linux OS 버전 xyz'에서 실행되도록 컴파일 된 응용 프로그램이있는 경우 다른 시스템 'ARM target, linux OS version xyz'에서 동일한 컴파일 된 바이너리를 실행할 수 있습니까?

ELF가 아니라면 그렇게 할 수 없습니다.

  1. 위의 내용이 사실이 아닌 경우, 유일한 방법은 관련 툴체인 '예 : arm-linux-gnueabi'를 사용하여 애플리케이션 소스 코드를 재 빌드 / 재 컴파일하는 것입니까?

간단한 대답은 그렇습니다. 복잡한 답변에는 에뮬레이션, 중간 표현, 번역기 및 JIT가 포함됩니다. i686 바이너리 만 "다운 그레이드"하여 i386 opcode 만 사용하는 경우를 제외하고는 여기에서는 흥미롭지 않을 수 있으며 ABI 픽스 업은 잠재적으로 네이티브 코드를 번역하는 것만 큼 어렵습니다. )

  1. 마찬가지로 'x86 대상, Linux OS 버전 xyz'에서 작동하는로드 가능한 커널 모듈 (장치 드라이버)이있는 경우 다른 시스템 'ARM 대상, Linux OS 버전 xyz'에서 동일한 컴파일 된 .ko를로드 / 사용할 수 있습니까 ?

아니요, ELF는이를 허용하지 않습니다.

  1. 위의 내용이 사실이 아닌 경우 유일한 방법은 관련 툴체인 '예 : arm-linux-gnueabi'를 사용하여 드라이버 소스 코드를 다시 빌드 / 재 컴파일하는 것입니까?

간단한 대답은 그렇습니다. FatELF를 사용하면 .ko다중 아키텍처 인 빌드를 만들 수 있지만 어느 시점에서 지원되는 모든 아키텍처에 대한 이진 버전을 만들어야합니다. 커널 모듈이 필요한 것은 종종 소스와 함께 제공되며 필요에 따라 빌드됩니다. 예를 들어 VirtualBox가이를 수행합니다.

이것은 이미 오래 걸리는 답입니다. 우회는 하나 더 있습니다. 커널 에는 이미 가상 머신이 내장되어 있지만 패킷을 일치시키는 데 사용되는 BPF VM 이 있습니다. 사람이 읽을 수있는 필터 ( "host foo and not port 22")는 바이트 코드로 컴파일되고 커널 패킷 필터가이를 실행합니다 . 새로운 eBPF 는 VM 코드가 모든 현대 리눅스에서 이식 가능하다는 이론에서 패킷만을위한 것이 아니라 llvm이이를 지원 하지만 보안상의 이유로 관리 규칙 이외의 다른 용도로는 적합하지 않을 것입니다.


이제 바이너리 실행 파일의 정의가 얼마나 관대했는지에 따라 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 파일 을 얻으 려면 test.woz디렉토리 계층 구조 로 ZIP 파일을 작성하십시오 .

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

각 arch / OS / libc 디렉토리 내에 (임의의 선택) 아키텍처 별 test바이너리 및 .so파일 과 같은 구성 요소를 배치 합니다. 이를 호출 할 때 필요한 서브 디렉토리가 tmpfs 인 메모리 파일 시스템 ( /mnt/tmpfs여기)으로 추출되어 호출됩니다.


0

베리 부팅, 문제의 일부를 해결 ..하지만 x86-32 / 64bit에 대 한 팔 hf, normall / regullAr 리눅스 배포판에서 실행하는 방법 문제를 해결하지 않습니다.

나는 그것이 isolinux (USB의 boatloader linux)에 regullar distro를 인식하고 승차 / 라이브로 hf로 변환 할 수있는 라이브 변환기에 내장되어야한다고 생각합니다.

왜? 각 리눅스가 베리 부트에 의해 arm-hf에서 작동하도록 변환 될 수 있다면 bery 부트 메커니즘에서 우리가 exaple eacher 또는 내장 우분투 creat 시동 디스크를 위해 사용하는 부트 isolinux에 빌드 할 수 있기 때문입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.