Skip to content
Advertisement

How to get the correct binary for my architecture. Trying to run ARM (.s) files

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 Answerhere 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.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement