I’ve used the following commands for cross-compilation on ubuntu to run simple.s
but am getting an error
> arm-linux-gnueabi-as -o simple.o simple.s > arm-linux-gnueabi-ld -o simple simple.o > ./simple bash: ./simple: cannot execute binary file: Exec format error > file simple simple: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, not stripped > uname -m x86_64
The commands are:
arm-linux-gnueabi-as -o simple.o simple.s arm-linux-gnueabi-ld -o simple simple.o ./simple
I tried to obtain the binary’s architecture by
file simple
and my machine’s architecture by
uname -m
and found that they were different. I believe getting the right binary for the architecture will solve the problem. Is that true?
Here is simple.s
.global _start @ comments start with the '@' character @ the _start label is the entry point to the program _start: @ program code here _exit: @ it is usual to indent instructions with TAB MOV R0, #65 @ arbitrary value MOV R7, #1 SWI 0
How can this issue be solved? Thx
Advertisement
Answer
You cannot natively execute a Linux executable compiled for a 32 bit ARM Linux system on a x86_64 Linux PC, because there are using different processors designed by different companies and, more importantly, using different instruction sets with different programming models.
For example, if you compile this simple C program with arm-linux-gnueabi-gcc
, the compiler will generate the following ARM assembly code:
add.c:
int add(int a, int b) { return a + b; }
add.s:
.arch armv7-a .file "add.c" .text .align 2 .global add .arch armv7-a .syntax unified .arm .fpu neon .type add, %function add: @ args = 0, pretend = 0, frame = 8 @ frame_needed = 1, uses_anonymous_args = 0 @ link register save eliminated. str fp, [sp, #-4]! add fp, sp, #0 sub sp, sp, #12 str r0, [fp, #-8] str r1, [fp, #-12] ldr r2, [fp, #-8] ldr r3, [fp, #-12] add r3, r2, r3 mov r0, r3 add sp, fp, #0 @ sp needed ldr fp, [sp], #4 bx lr .size add, .-add .ident "GCC: (GNU Toolchain for the A-profile Architecture 10.2-2020.11 (arm-10.16)) 10.2.1 20201103" .section .note.GNU-stack,"",%progbits
Now, if you compile it with x86_64-linux-gnu-gcc
, it will generate code for the x86_64/amd64 architecture:
add.s:
.file "add.c" .text .globl add .type add, @function add: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl %edi, -4(%rbp) movl %esi, -8(%rbp) movl -4(%rbp), %edx movl -8(%rbp), %eax addl %edx, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size add, .-add .ident "GCC: (Debian 8.3.0-6) 8.3.0" .section .note.GNU-stack,"",@progbits
As you can see, the assembly is completely different, as will be the generated machine code once they will have been assembled and linked. Reading the section titled ‘Long Answer‘ here will make it obvious.
Different architectures means different CPU: arm-linux-gnueabi-as
can only compile programs for and ARM CPU without hardware support for floating point operations running Linux: there is a hint in the compiler name, which is build from the architecture, operating system, and ABI it can compile programs for:
[arm]-[linux]-[gnueabi] , or [x86_64]-[linux]-[gnu] for example. See here for a short explanations of what ‘target triplets’ are in the context of the gcc compiler.
Cross-compiling is the action of compiling a program targeting a computer with CPU cpu#1 running operating system os#1 on a different computer with CPU cpu#2 running operation system os#2.
In your case, you are compiling a program designed for running on a 32 bit ARM CPU running Linux on a 64 bit Intel CPU (x86_64/amd64) running Linux.
Bus cross-compiling does not allow ‘cross-executing’: for doing so, you need to use an emulator such as qemu-arm
, either explicitly, or by using binfmt-support
as explained here.
If something is not clear in this answer, or if you think you are still missing a crucial piece of information, feel free to comment or augment your question accordingly.