I tried assembling some intermediate code generated by gcc. I used the command as -o hello hello.s
, which, as far as I can tell, is the correct syntax. When I tried to run the program, it said bash: ./hello: cannot execute binary file
. It doesn't seem like there's a problem with the assembly code, since it was the code generated by gcc, and it doesn't seem like there's anything wrong with how I invoked the assembler, since that seems to be the right syntax according to this manual. Can anyone help me with this?
Assume that your assembly file is called hello.s and looks something like (assuming a 32-Bit Linux target):
.data
msg: .asciz "Hello World\n"
msglen = .-msg
.text
.global _start
_start:
/* Use int $0x80/eax=4 to write to STDOUT */
/* Output Hello World */
mov $4, %eax /* write system call */
mov $0, %ebx /* File descriptor 0 = STDOUT */
mov $msg, %ecx /* The message to output */
mov $msglen, %edx /* length of message */
int $0x80 /* make the system call */
/* Exit the program with int $0x80/eax=1 */
mov $1, %eax /* 1 = exit system call */
mov $0, %ebx /* value to exit with */
int $0x80 /* make the system call */
This is a 32-bit Linux assembler program in AT&T syntax that displays Hello World
to standard output using 32-bit system calls via int $0x80
. It doesn't use any C functions so can be assembled with the GNU assembler as
and linked with the GNU linker ld
to produce a final executable.
as --32 hello.s -o hello.o
ld -melf_i386 hello.o -o hello
The first line assembles hello.s into a 32-bit ELF object called hello.o . hello.o is then linked to a 32-bit ELF executable called hello with the second command. The GNU linker assumes by default that your program starts execution at the label _start
.
Alternatively you can use GCC to assemble and link this program with this command:
gcc -nostdlib -m32 hello.s -o hello
This will produce a 32-bit ELF executable called hello . The -nostdlib
tells GCC not to link in the C runtime library and allows us to use _start
as our program's entry point.
If your assembler program is intended to be linked to the C runtime and library so that it can utilize functions like C's printf then things are a bit different. Assume you have this program that needs printf (or any of the C library functions):
.data
msg: .asciz "Hello World\n"
.text
.global main
main:
push %ebp /* Setup the stack frame */
mov %esp, %ebp /* Stack frames make GDB debugging easier */
push $msg /* Message to print */
call printf
add $4,%esp /* cleanup the stack */
xor %eax, %eax /* Return 0 when exiting */
mov %ebp, %esp /* destroy our stack frame */
pop %ebp
ret /* Return to C runtime that called us
and allow it to do program termination */
Your entry point now must be main
on most *nix type systems. The reason is that the C runtime will have an entry point called _start
that does C runtime initialization and then makes a call to the function called main
which we supply in our assembler code. To compile/assemble and link this we can use:
gcc -m32 hello.s -o hello
Note: on Windows the entry point called by the C runtime is _WinMain
, not main
.
In the comments you also asked about NASM so I'll provide some information when assembling with it. Assume that your assembly file is called hello.asm and looks something like (It doesn't require the C runtime libraries):
SECTION .data ; data section
msg db "Hello World", 13, 10
len equ $-msg
SECTION .text ; code section
global _start ; make label available to linker
_start: ; standard gcc entry point
mov edx,len ; length of string to print
mov ecx,msg ; pointer to string
mov ebx,1 ; write to STDOUT (file descriptor 0)
mov eax,4 ; write command
int 0x80 ; interrupt 80 hex, call kernel
mov ebx,0 ; exit code, 0=normal
mov eax,1 ; exit command to kernel
int 0x80 ; interrupt 80 hex, call kernel
Then to build it into an executable you can use commands like these:
nasm -f elf32 hello.asm -o hello.o
gcc -nostdlib -m32 hello.o -o hello
The first command assembles hello.asm to the ELF object file hello.o . The second line does the linking. -nostdlib
excludes the C runtime from be linked in (functions like _printf
etc wouldn't be available). The second line links hello.o to the executable hello .
Alternatively you can skip using GCC and use the linker directly like this:
nasm -f elf32 hello.asm -o hello.o
ld -melf_i386 hello.o -o hello
If you need the C runtime and library for calling things like printf
then it is a bit different. Assume you have this NASM code that needs printf
:
extern printf
SECTION .data ; Data section, initialized variables
msg: db "Hello World", 13, 10, 0
SECTION .text ; Code section.
global main ; the standard gcc entry point
main: ; the program label for the entry point
push ebp ; Setup the stack frame
mov ebp, esp ; Stack frames make GDB debugging easier
push msg ; Message to print
call printf
add esp, 4 ; Cleanup the stack
mov eax, 0 ; Return value of 0
mov esp, ebp ; Destroy our stack frame
pop ebp
endit:
ret ; Return to C runtime that called us
; and allow it to do program termination
Then to build it into an executable you can use commands like these:
nasm -f elf32 hello.asm -o hello.o
gcc -m32 hello.o -o hello