Cannot execute binary file (GCC for windows) - gcc

I'm trying to compile the piece of assembly code below using gcc. I have finally got it to the point that it compiles an object file, but when I try and run it it get an error back saying 'cannot execute binary file'. I am on windows 10 version 1511.
I am using the msys terminal and compiling by entering
gcc -c main.s -o main.o
I try and execute the file by entering
./main.o
And I get back the error
./main.o: ./main.o: cannot execute binary file
The assembly code is:
.section .text
.global main
main:
mov $4,%eax
mov $1,%ebx
mov $message,%ecx
mov msglength,%edx
int $0x80
mov $1, %eax
mov $0, %ebx
int $0x80
.section .data
message: .ascii "Hello world!"
msglength: .word 12
Any help would be much appreciated.

That is a Linux program and will not work on Windows.
As described in the comments, you need to link the program, remove -c from the gcc command line.

Related

Fix relocations for global variables in position-independent executables with GCC

I'm looking for a gcc command-line flag or other settings to produce GOTOFF relocations rather than GOT relocations for my statically linked, position-independent i386 executable. More details on what I was trying below.
My source file g1.s looks like this:
extern int answer;
int get_answer1() { return answer; }
My other source file g2.s looks like this:
extern int answer;
int get_answer2() { return answer; }
I compile them with gcc -m32 -fPIE -Os -static -S -ffreestanding -fomit-frame-pointer -fno-unwind-tables -fno-asynchronous-unwind-tables g1.c for i386.
I get the following assembly output:
.file "g1.c"
.text
.globl get_answer1
.type get_answer1, #function
get_answer1:
call __x86.get_pc_thunk.cx
addl $_GLOBAL_OFFSET_TABLE_, %ecx
movl answer#GOT(%ecx), %eax
movl (%eax), %eax
ret
.size get_answer1, .-get_answer1
.section .text.__x86.get_pc_thunk.cx,"axG",#progbits,__x86.get_pc_thunk.cx,comdat
.globl __x86.get_pc_thunk.cx
.hidden __x86.get_pc_thunk.cx
.type __x86.get_pc_thunk.cx, #function
__x86.get_pc_thunk.cx:
movl (%esp), %ecx
ret
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
.section .note.GNU-stack,"",#progbits
Here is how to reproduce this behavior online with GCC 7.2: https://godbolt.org/g/XXkxJh
Instead of GOT above, I'd like to get GOTOFF, and the movl %(eax), %eax should disappear, so the assembly code for the function should look like this:
get_answer1:
call __x86.get_pc_thunk.cx
addl $_GLOBAL_OFFSET_TABLE_, %ecx
movl answer#GOTOFF(%ecx), %eax
ret
I have verified that this GOTOFF assembly version is what works, and the GOT version doesn't work (because it has an extra pointer indirection).
How can I convince gcc to generate the GOTOFF version? I've tried various combinations of -fPIC, -fpic, -fPIE, -fpie, -pie, -fno-plt. None of them worked, all of them made gcc produce the GOT version.
I couldn't find any i386-specific flag on https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html or any generic flag here: https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html
In fact, I'm getting GOTOFF relocations for "..." string literals, and I also want to get them for extern variables.
The final output is a statically linked executable in a custom binary format (for which I've written a GNU ld linker script). There is no dynamic linking and no shared libraries. The address randomization is performed by a custom loader, which is free to load the executable to any address. So I do need position-independent code. There is no per-segment memory mapping: the entire executable is loaded as is, contiguously.
All the documentation I've been able to find online talk about position-independent executables which are dynamically linked, and I wasn't able to find anything useful there.
I wasn't able to solve this with gcc -fPIE, so I solved it manually, by processing the output file.
I use gcc -Wl,-q, with an output ELF executable file containing the relocations. I post-process this ELF executable file, and I add the following assembly instructions to the beginning:
call next
next:
pop ebx
add [ebx + R0 + (after_add - next)], ebx
add [ebx + R1 + (after_add - next)], ebx
add [ebx + R2 + (after_add - next)], ebx
...
after_add:
, where R0, R1, R2 ... are the addresses of R_386_32 relocations in the ELF executable. The In use objdump -O binary prog.elf prog.bin', and nowprog.bin' contains position-independent code, because it starts with the `add [ebx + ...], ebx' instructions, which do the necessary relocations to the code when the code starts running.
Depending on the execution environment, the gcc flag -Wl,-N is needed, to make the .text section writable (the `add [ebx + ...], ebx' instructions need that).

Error "16434 illegal hardware instruction ./a.out" when running x86 executable

I'm learning the basics of x86 via this free book.
Keep in mind this is specific to macOS x86 compared to Linux x86.
Its made for GNU Linux, so I have to change some of the code which is probably where I went wrong. I took this code snippet:
.section .data
.section .text
.globl _start
_start:
movl $1, %eax
movl $0, %ebx
int $0x80
After a bit of googling about x86 on macOS I turned that bit of code into this:
.data
.text
.globl _main
_main:
movl $1, %eax
movl $0, %ebx
int $0x80
I compiled this using gcc test.s which compiles it into a.out. When trying to run it using ./a.out I get the error [1] 17301 illegal hardware instruction ./a.out.
Any help is appreciated, thanks!
#Jester helped me out. You can view the comment on my question, but basically call convention is different for macOS. I found this resource which helped me out.

Nasm Dwarf Error Bad Offset

I have a simple Hello World program for Windows in pure x86 assembly code that I have compiled and linked with nasm and ld. The problem I am running into is that I can't get DWARF debugging to work. I am using gdb from Mingw64 (i686-posix-dwarf-rev1). This same problem happens if I use gcc to link instead of ld. But, the program builds fine, and if I use STABS debugging, then everything is fine and dandy.
EDIT: Oops, I completely forgot to give the error that gdb shows.
...Dwarf Error: bad offset (0x407000) in compilation unit header (offset 0x0
+ 6) [in module C:\Projects\AsmProjects\HelloWorldWin32\bin\x86\hello32.exe]
(no debugging symbols found)...done
The versions of each program are:
gdb 7.10.1
nasm 2.12.02
ld 2.25
gcc 6.2.0
These are the flags I'm sending to nasm: -f elf32 -Fdwarf -g
These are the flags for gcc link: -o $(BDIR)/x86/$#.exe $^ -L$(Mingw64-x86libs) -lkernel32 -luser32
And these are from ld link:
-mi386pe -o $(BDIR)/x86/$#.exe $^ -L$(Mingw64-x86libs) -lkernel32 -luser32
I have a pretty big makefile, so I'm trying to give the least information that is absolutely neccessary.
Here is the source code for the program:
global _main
extern _GetStdHandle#4
extern _WriteFile#20
extern _ExitProcess#4
section .text
_main:
push ebp
mov ebp,esp
; GetstdHandle( STD_OUTPUT_HANDLE)
push -11
call _GetStdHandle#4
mov ebx, eax
; WriteFile( hstdOut, message, length(message), &bytes, 0);
push 0
push esp
push message_end
push message
push ebx
call _WriteFile#20
; ExitProcess(0)
push 0
call _ExitProcess#4
section .data
message db 'Hello, World',10
message_end equ $ - message
This is not a proper answer but was too long for the comment section.
I compiled on Ubuntu and then ran dwarfdump
It gave an error that may be related to the offset error.
dwarfdump ERROR: dwarf_get_globals: DW_DLE_PUBNAMES_VERSION_ERROR (123)
From a similar error on LLVM, I conclude that the dwarf version information is possibly corrupt or unsupported.
This post indicates that the dwarf information is sensitive to the proper section names. The example appears to have the section names right however.
Have you tried a 64-bit version? Perhaps a clue will appear.
This program appears to work fine Ubuntu. Can you try it on Mingw64?
section .text
global _start ;must be declared for linker (ld)
_start: ;tell linker entry point
mov edx,len ;message length
mov ecx,msg ;message to write
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg db 'Hello, world!',0xa ;our dear string
len equ $ - msg ;length of our dear string

GNU assembler did not produce a program that I can execute

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?
Working with GNU Assembler
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 mainon 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.
Working with NASM
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
Neither a compiler nor an assembler generates an executable file. Both generate an object file, which can then be linked with other object and/or library files to generate an executable.
The command gcc -c, for example, invokes just the compiler; it can take a source file like hello.c as input and generate an object file like hello.o as output.
Likewise, as can take an assembly language source file like hello.s and generate an object file like hello.o.
The linker is a separate tool that generates executables from object files.
It just happens that compiling and linking in one step is so convenient that that's what the gcc command does by default; gcc hello.c -o hello invokes the compiler and the linker to generate an executable file.
Note that the gcc command isn't just a compiler. It's a driver program that invokes the preprocessor, the compiler proper, the assembler, and/or the linker. (The preprocessor and assembler, can be thought of as components of the compiler, and in some cases they aren't even separate programs, or a compiler can generate machine object code instead of assembly code.)
In fact, you can perform the same multi-step process in one command for assembly language as well:
gcc hello.s -o hello
will invoke the assembler and linker and generate an executable file.
This is specific to gcc (and probably to most other compilers for Unix-like systems). Other implementations might be organized differently.

PIE disabled. Absolute addressing when asm programming with gcc on mac OS X

I wrote the code below. I want to compile it using gcc on mac OS X,
but I get a message saying "PIE disabled. Absolute addressing" when I run gcc.
I googled it, but cannot find a solution.
Please advise.
hello.s file:
.data
hello: .string "Hello World!\n"
.text
.globl _main
_main:
push %rbp
mov %rsp, %rbp
movabs $hello, %rdi
call _printf
leave
ret
The error:
ld: warning: PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in
code signed PIE, but used in _main from /var/folders/xs/4z9kr_n93111fhv9_j1dd9gw0000gn/T/ex2_64-369300.o.
To fix this warning, don't compile with -mdynamic-no-pic or link with -Wl,-no_pie
Looks like there are a couple solutions:
Link with -Wl,-no_pie:
clang -o hello hello.s -Wl,-no_pie
Don't use absolute addressing.
.data
hello: .string "Hello World!\n"
.text
.globl _main
_main:
push %rbp
mov %rsp, %rbp
lea hello(%rip), %rdi
mov $0, %rax
call _printf
leave
ret
Then you can compile and run:
host % clang -o hello hello.s
host % ./hello
Hello World!
The bit about zeroing out al is mentioned in section 3.5.7 of System V Application Binary Interface. Here's the relevant excerpt:
When a function taking variable-arguments is called, %al must be set
to the total num- ber of floating point parameters passed to the
function in vector registers.
In your case this is zero. You are passing in zero floating point parameters.

Resources