GNU assembler did not produce a program that I can execute - gcc

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.

Related

Including header file in assembly file

I am trying to include a header file containing a macro into my main assembly file, but the compilation fails.
Below is my main.S file
#include "common.h"
BEGIN
mov $0x0E40, %ax
int $0x10
hlt
Below is my common.h file :
.macro BEGIN
LOCAL after_locals
.code16
cli
ljmp $0, $1f
1:
xor %ax, %ax
/* We must zero %ds for any data access. */
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %bp
/* Automatically disables interrupts until the end of the next instruction. */
mov %ax, %ss
/* We should set SP because BIOS calls may depend on that. TODO confirm. */
mov %bp, %sp
/* Store the initial dl to load stage 2 later on. */
mov %dl, initial_dl
jmp after_locals
initial_dl: .byte 0
after_locals:
.endm
Both files are in same directory. When I do the compilation :
$ as --32 -o main.o main.S
main.S: Assembler messages:
main.S:2: Error: no such instruction: `begin'
What am I missing? I did a little research and got this answer in SO, but its not helpful. Please help.
$ as --32 -o main.o main.S
as is just an assembler, it translates assembly source to object code. It does not run the C preprocessor which is supposed to expand #include.
(# is the comment character in GAS syntax for x86 so the line is treated as a comment if it's seen by the assembler instead of replaced by CPP)
What you can do:
Use gcc to assemble, with appropriate file suffix (.S or .sx), it will run the C preprocessor before running the assembler.
Add -v to see what commands gcc is invoking.
If your source has a different suffix, you can -x assembler-with-cpp source.asm.
If you want to see the intermediate result after preprocessing, add -save-temps. This will write a .s file with the preprocessed source.
If you want to pass down a command line option to as, you can for example -Wa,--32. However, it is better to use options which the compiler driver understands like -m32 or -m16 in the present case. The driver knows about such options, for example it will also cater for appropriate options when linking, provided you are linking with gcc -m32 ... as noted below.
Use a .include assembler directive which is handled by the assembler itself, not the C preprocessor.
Note: In case 1. adding include search paths by means of -I path might not work as expected: The compiler driver (gcc in this case) will add -I path only to the assembler's command line if it knows that it's the GNU assembler. You can tell this when the compiler is configured by configure flag --with-gnu-as.
Note: Similar applies to linking. You probably do not want to call the linker (ld by hand) unless you're making a static executable or flat binary; use gcc or g++ instead if you're making a normal executable to run on the host system. It will add many options needed for linking like multilib paths, search paths, etc. which you do not want to fiddle by hand.
(int $0x10 is a 16-bit BIOS call, though, which won't work under a modern mainstream OS, only DOS or a legacy BIOS bootloader.)
If your header file is just assembly then include with .include "file" directive in main.S. But this way of doing would insert the code the location where its included.

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

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

How to link 32-bit Nasm assembly object code on a 64-bit windows computer

I found the following code from http://www.dreamincode.net/forums/topic/328714-my-program-keeps-crashing/.
global start
;~ msvcrt.dll
extern _printf
%define printf _printf
;~ kernel32.dll
extern ExitProcess, GetCommandLineW, LocalFree
%define GetCommandLine GetCommandLineW
;~ shell32.dll
extern CommandLineToArgvW
%define CommandLineToArgv CommandLineToArgvW
SECTION .data
message db 'Hello, World', 13, 10, 0
fmtstr db "%s", 0
fmtstrCL db "Arg","%d", " = ", "%S", 13, 10, 0
section .bss
pNumArgs resd 1
section .text
start:
call GetCommandLine
push pNumArgs
push eax
call CommandLineToArgv
mov esi, eax
mov ebx, [pNumArgs]
DisplayArgs:
dec ebx
push dword[esi + 4 * ebx]
inc ebx
push ebx
push fmtstrCL
call printf
add esp, 4 * 3
dec ebx
jnz DisplayArgs
push esi
call LocalFree
push message ; Push address of "Hello, world!" onto the stack
push fmtstr ; push address of formatter onto the stack
call printf ; Print the message
add esp, 4 * 2 ; adjust stack pointer
push 0
call ExitProcess
My goal is to learn assembly language by reading other people's code and eventually write my own. I cannot figure out how to link 32-bit assembly programs on my 64-bit windows computer.
To assemble the program I use the command:
nasm -f win32 hello32.asm -o hello32.o
To link the object file I use:
gcc hello32.o -o hello32.exe
After I issue the link command I get the following error:
C:/Program Files/mingw-w64/x86_64-5.2.0-posix-seh-rt_v4-rev0/mingw64/bin/../lib/
gcc/x86_64-w64-mingw32/5.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: i386 arc
hitecture of input file `hello32.o' is incompatible with i386:x86-64 output
hello32.o:hello32.asm:(.text+0x24): undefined reference to `_printf'
hello32.o:hello32.asm:(.text+0x3f): undefined reference to `_printf'
C:/Program Files/mingw-w64/x86_64-5.2.0-posix-seh-rt_v4-rev0/mingw64/bin/../lib/
gcc/x86_64-w64-mingw32/5.2.0/../../../../x86_64-w64-mingw32/lib/../lib/libmingw3
2.a(lib64_libmingw32_a-crt0_c.o):crt0_c.c:(.text.startup+0x2e): undefined refere
nce to `WinMain'
collect2.exe: error: ld returned 1 exit status
I am using 64-bit mingw binaries that are supposed to be compatible with making 32-bit programs. I have tried switching to 32-bit mingw binaries and I get a massive amount of undefined reference errors. I can link simple skeleton files without any problems using the above commands. I have no idea what I am doing wrong and I would appreciate any guidance someone could give me.
i386 architecture of input file `hello32.o' is incompatible with i386:x86-64 output
NASM has created a 32 bit object file, but you are trying to link a 64 bit executable. You could try to use the -m32 switch to create a 32 bit executable, but you already found out that this causes another bunch of errors. I do not have a solution for that either.
To link your executable, use a 32 bit MingW environment. I tried MinGW4.6.2 32 bit which worked well.
Alternatively, you can use the linker (link.exe) from a Microsoft Visual Studio installation.
https://github.com/afester/CodeSamples/tree/master/Asm/nasm_win32 shows a hello world example together with a Makefile which uses the Visual Studio linker. Alternatively, using gcc helloworld.obj -o hello32.exe from a MingW32 installation works also.
Two issues:
You're using the option -f win32 but asking for the object file in *.o extension. The two formats, .o and .obj are not compatible. But of course, you're free to specify your own extension, and so nasm will obediently assemble your code into a file with i386 arc format .o file.
Next, you're asking gcc to build that hello32.exe, using the file hello32.o. Effectively, you gave gcc an arc format .o file, and asked to build a 64-bit PE format executable out of it. And then (naturally) gcc complains:
i386 architecture of input file `hello32.o' is incompatible with i386:x86-64 output
which is correct.
Two ways you can fix this:
Assemble with: nasm -fwin32 hello32.asm and then, link with gcc -m32 hello32.obj -o hello32.exe
Assemble with: nasm -fobj hello32.asm and then link with alink -subsys console -oPE hello32.o. You can get alink from here.
Let me know which worked for you.
P.S. I have outlined the problems I have faced myself in this blog, hope that helps.

Emacs gdb - display arrow when debugging assembly

I'm trying to debug an assembly program using gdb and Emacs. My problem is that, when I try to debug step-by-step, it doesn't show a pointer arrow at the current executing line. The code I'm trying to debug is:
SECTION .data ; Section containing initialised data
EatMsg: db "Eat at Joe's!",10
EatLen: equ $-EatMsg
SECTION .bss ; Section containing uninitialized data
SECTION .text ; Section containing code
global _start ; Linker needs this to find the entry point!
_start:
nop ; This no-op keeps gdb happy...
mov eax,4 ; Specify sys_write call
mov ebx,1 ; Specify File Descriptor 1: Standard Output
mov ecx,EatMsg ; Pass offset of the message
mov edx,EatLen ; Pass the length of the message
int 80H ; Make kernel call
MOV eax,1 ; Code for Exit Syscall
mov ebx,0 ; Return a code of zero
int 80H ; Make kernel call
and I'm compiling with these lines:
nasm -f elf -g -F stabs eatsyscall.asm -l eatsyscall.lst
ld -melf_i386 -o eatsyscall eatsyscall.o
What I see in Emacs is that. In this screenshot I'm currently executing the line after the breakpoint and no pointer to that line appears. Is it possible to have one?
first of all, i hope you are still looking for the solution, it has been 2 years ! if you are, then try coaxing nasm to generate debugging information with DWARF instead of STAB i.e the following
nasm -f elf -g -F dwarf eatsyscall.asm ...
that seems to work for me (TM)
Try to download nasm2.5 or the latest available, it should work

Resources