x86 Assembly with gas on linux: multiple definitions of 'main' - linux

I'm starting out with programming in Assembly in x86 and I'm following a guide for that. I'm using gas to compile on a linux virtual machine.
I'm trying to run a simple empty program where main routine exits the program immediately. That's the first task in the guide I'm following. My code is saved in a file hello.s and it looks like this:
.global main
main:
movq %rsp, %rbp
mov $0, %rdi
call exit
In the terminal I navigate to the directory of the file and try to run it like this:
gcc -o hello.o hello.s -no-pie ./hello.s
I get an error saying:
/tmp/cc62hr1F.o: In function 'main':
(.text+0x0): multiple definition of 'main'
/tmp/ccwMutY1.o(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
What does this error mean and how to fix it? Thank you in advance.

EDIT/SOLUTION: I figured out what was wrong. In the terminal I should run it like this:
gcc -o hello.o hello.s -no-pie
./hello.o
These are two seperate commands. I wrote them in one line. And the file to run has to have the extensions .o not .s

Related

How do you assemble, link and run a .s file in linux?

I'm getting a weird error message when trying to assemble and run a .s file using AT&T Intel Syntax. Not sure if I'm even using the correct architecture to begin with, or if I'm having syntax errors, if I'm not using the correct commands to assemble and link, etc. Completely lost and I do not know where to begin.
So basically, I have a file called yea.s , which contains some simple assembler instructions. I then try to compile it using the command as yea.s -o yea.o and then link is using ld yea.o -o yea. When running ld, I get this weird message:ld: warning: cannot find entry symbol _start; defaulting to 000000440000.
This is the program im trying to run, very simple and doesn't really do anything.
resMsg: .asciz "xxxxxxxx"
.text
.global main
main:
pushq $0
ret
I just cannot figure out what's going on. Obviously, this is for school homework. I'm not looking for the answer to the homework, obviously, but this is the starting point to where I can actually start the coding. And I just cant figure out how to simple run the program, which it doesn't say in the assignment. Anyway, thanks in advance guys!
Linux executables require an entry point to be specified. The entry point is the address of the first instruction to be executed in your program. If not specified otherwise, the link editor looks for a symbol named _start to use as an entry point. Your program does not contain such a symbol, thus the linker complains and picks the beginning of the .text section as the entry point. To fix this problem, rename main to _start.
Note further that unlike on DOS, there is nothing to return to from _start. So your attempt to return is going to cause a crash. Instead, call the system call sys_exit to exit the program:
mov $0, %edi # exit status
mov $60, %eax # system call number
syscall # perform exit call
Alternatively, if you want to use the C runtime environment and call functions from the C library, leave your program as is and instead assemble and link using the C compiler driver cc:
cc -o yea yea.s
If you do so, the C runtime environment provides the entry point for you and eventually tries to call a function main which is where your code comes in. This approach is required if you want to call functions from the C library. If you do it this way, make sure that main follows the SysV ABI (calling convention).
Note that even then your code is incorrect. The return value of a function is given in the eax (resp. rax) register and not pushed on the stack. To return zero from main, write
mov $0, %eax # exit status
ret # return from function
In all currently supported versions of Ubuntu open the terminal and type:
sudo apt install as31 nasm
as31: Intel 8031/8051 assembler
This is a fast, simple, easy to use Intel 8031/8051 assembler.
nasm: General-purpose x86 assembler
Netwide Assembler. NASM will currently output flat-form binary files, a.out, COFF and ELF Unix object files, and Microsoft 16-bit DOS and Win32 object files.
If you are using NASM in Ubuntu 18.04, the commands to compile and run an .asm file named example.asm are:
nasm -f elf64 example.asm # assemble the program
ld -s -o example example.o # link the object file nasm produced into an executable file
./example # example is an executable file

Assembly executable on Termux now produces Illegal instruction error [duplicate]

This question already has an answer here:
How to implement system call in ARM64?
(1 answer)
Closed 3 years ago.
Can you let me know what I'm doing wrong?
I'm new to assembly programming and am unfamiliar with the various options in ld.
I've been trying to use the yasm compiler initially but then realised that as is the way to go for the ARM architecture while composing GNU compliant assembly code.
Better luck running as from the binutils package, i.e. the GNU assembler. But the assembly code has to be ARM-compliant.
The following is the code within arm.s:
.text /* Start of the program code section */
.global main /* declares the main identifier */
.type main, %function
main: /* Address of the main function */
/* Program code would go here */
BR LR
/* Return to the caller */
.end /* End of the program */
The above was throwing an Illegal Instruction error. That can be fixed
by substituting ret for BR LR. This is new to ARM V8.
ARM, a RISC architecture, is not supported by YASM.
My build file is as follows:
#/usr/bin/env bash
#display usage
[ $# -eq 0 ] && { echo "Usage: $0 <File Name without extension> ";exit 1; }
set +e
rm -f $1.exe $1 $1.o
as -o $1.o $1.s
[ -e $1.o ] && { file $1.o;}
gcc -s -o $1.exe $1.o -fpic
ld -s -o $1 -pie --dynamic-linker /system/bin/linker64 /data/data/com.termux/files/usr/lib/crtbegin_dynamic.o $1.o -lc -lgcc -ldl /data/data/com.termux/files/usr/lib/crtend_android.o
[ -e $1.exe ] && { file $1.exe;nohup ./$1.exe; }
[ -e $1 ] && { file $1;nohup ./$1;}
set -e
The code was causing either a segmentation fault or a bus error earlier.
I was able to run a program or two without any segmentation or bus errors with the updated build file above. I set up the build file to produce two executables, one using gcc and the other ld, since some online tutorials use ld instead of gcc for the linking step. Using the verbose setting of gcc, you can look at the options passed to the linker and thus mimic the same for the linker independently.
There may be some redundant settings that I've missed.
You can access updates to the source code and build file at
Learn Assembly.
Check out this resource from Keil here. arm Keil product guides
More resources:
https://thinkingeek.com/2016/10/08/exploring-aarch64-assembler-chapter1/
How to link a gas assembly program that uses the C standard library with ld without using gcc?
While the above problem appears to be fixed for now, I have errors running the following code:
.text
.global main
main:
mov w0, #2
mov w7, #1 // request to exit program
svc 0
I obtain an illegal instruction error when I try to execute the code.
Secondly, if I alter the main to _start (since I don't want to be using main all the time), I have the following error from the buildrun script.
./buildrun myprogram
/data/data/com.termux/files/usr/bin/aarch64-linux-android-ld: myprogram.o: in function `_start': (.text+0x0): multiple definition of `_start'; /data/data/com.termux/files/usr/lib/crtbegin_dynamic.o:crtbegin.c:(.text+0x0): first defined here /data/data/com.termux/files/usr/bin/aarch64-linux-android-ld: /data/data/com.termux/files/usr/lib/crtbegin_dynamic.o: in function `_start_main': crtbegin.c:(.text+0x38): undefined reference to `main
/data/data/com.termux/files/usr/bin/aarch64-linux-android-ld: crtbegin.c:(.text+0x3c): undefined reference to `main' clang-8: error: linker command failed with exit co
de 1 (use -v to see invocation)
ld: myprogram.o: in function `_start': (.text+0x0): multiple definition of `_start'; /data/data/com.termux/files/usr/lib/crtbegin_dynamic.o:crtbegin.c:(.text+0x0): first defined here ld: /data/data/com.termux/files/usr/lib/crtbegin_dynamic.o: in function `_start_main': crtbegin.c:(.text+0x38): undefined reference to `main'
ld: crtbegin.c:(.text+0x3c): undefined reference to `main'
How do I create programs with entry points other than main?
I want to be able to :
Create a statically linked executable that works.
Create an executable that has a function named _start instead of main.
This file builds static executables that don't use main or call any library calls.
Create a dynamically linked executable with an entry point other than main.
My build file handles this, sort of, with the entry point as second parameter.
Create an executable that uses supervisor call svc to exit without throwing an illegal instruction error as against using ret.
I was able to call svc by setting the system call number in register X8 as against W7 in version 7 ARM. Additionally, ARM 64 has renumbered the system call numbers as per the following header file.
https://github.com/torvalds/linux/blob/v4.17/include/uapi/asm-generic/unistd.h
https://reverseengineering.stackexchange.com/q/16917
.data
.balign 8
labs: .asciz "Azeria Labs\n" //.asciz adds a null-byte to the end of the string .balign 8 after_labs: .set size_of_labs, after_labs - labs .balign 8 addr_of_labs: .dword labs .balign 8 .text
.global main
main:
mov x0, #1 //STDOUT ldr x1,addr_of_labs //memory address of labs mov w2, #size_of_labs //size of labs mov x8,#64 svc #0x0 // invoke syscall _exit: mov x8, #93 //exit syscall
svc #0x0 //invoke syscall
The above code was ported from the example code listed below.
https://azeria-labs.com/writing-arm-shellcode/
Compacting the data section into one instead of splitting it as in the example from the site mitigates the relocation errors while linking.
Other useful references:
https://thinkingeek.com/2013/01/09/arm-assembler-raspberry-pi-chapter-1/
*Check the comment by ehrt74 on the above post for the motivation to explore svc call further. *
Yasm is an x86 assembler. It cannot produce executables for an ARM processor.
The tutorials you are working with are describing x86 assembly. They are intended to be followed on an x86 system.

Linker error when calling printf from _start [duplicate]

This question already has answers here:
Assembling 32-bit binaries on a 64-bit system (GNU toolchain)
(2 answers)
Closed 6 years ago.
I tried to write simple program without main
segment .data
fmt db "test", 0xa, 0
segment .text
global _start
extern printf
_start:
lea rdi, [fmt] ; print simple string
xor eax, eax
call printf
mov eax, 60 ; exit successfully
xor edi, edi
syscall
Compile:
yasm -f elf64 main.s; ld -o main main.o
Got
main.o: In function `_start':
main.s:(.text+0xb): undefined reference to `printf'
How should one fix this?
Cause of Your Error
The reason you get undefined reference to printf while linking is because you didn't link against the C library. As well, when using your own _start label as an entry point there are other issues that must be overcome as discussed below.
Using LIBC without C Runtime Startup Code
To make sure you are using the appropriate dynamic linker at runtime and link against the C library you can use GCC as a frontend for LD. To supply your own _start label and avoid the C runtime startup code use the -nostartfiles option. Although I don't recommend this method, you can link with:
gcc -m64 -nostartfiles main.o -o main
If you wish to use LD you can do it by using a specific dynamic linker and link against the C library with -lc. To link x86_64 code you can use:
ld -melf_x86_64 --dynamic-linker=/lib64/ld-linux-x86-64.so.2 main.o -lc -o main
If you had been compiling and linking for 32-bit, then the linking could have been done with:
ld -melf_i386 --dynamic-linker=/lib/ld-linux.so.2 main.o -lc -o main
Preferred Method Using C Runtime Startup Code
Since you are using the C library you should consider linking against the C runtime. This method also works if you were to create a static executable. The best way to use the C library is to rename your _start label to main and then use GCC to link:
gcc -m64 main.o -o main
Doing it this way allows you to exit your program by returning (using RET) from main the same way a C program ends. This also has the advantage of flushing standard output when the program exits.
Flushing output buffers / exit
Using syscall with EAX=60 to exit won't flush the output buffers. Because of this you may find yourself having to add a newline character on your output to see output before exiting. This is still not a guarantee you will see what you output with printf. Rather than the sys_exit SYSCALL you might consider calling the C library function exit. the MAN PAGE for exit says:
All open stdio(3) streams are flushed and closed. Files created by tmpfile(3) are removed.
I'd recommend replacing the sys_exit SYSCALL with:
extern exit
xor edi, edi ; In 64-bit code RDI is 1st argument = return value
call exit
The printf function is provided by the C standard library, libc. To use it, you need to pass -lc to the linker:
ld -o main main.o -lc
I recommend you to use the C compiler as a frontend for the linker to get possible other flags right, too:
cc -o main -nostartfiles main.o
Note that since your program doesn't initialize the C standard library, e parts of it may not work as expected. If you want to use the C standard library in your assembly program, I recommend you to make your assembly program start from main and to link it by invoking the C compiler:
yasm -f elf64 main.s
cc -o main main.o

GDB Debugger Error

I am very sorry, if my English is bad. This problem is getting me for days.
I have a simple C source code with a sub function which I am examining. First I am creating the .out file with gcc. This file I am examining with GDB. But if I want to disassemble the called function I always get an error message from gdb.
Prolog:
unix#unix-laptop:~/booksrc $ gcc -g stack_example.c
unix#unix-laptop:~/booksrc $ gdb -q ./a.out
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) disass main
Dump of assembler code for function main:
0x08048357 <main+0>: push %ebp
0x08048358 <main+1>: mov %esp,%ebp
0x0804835a <main+3>: sub $0x18,%esp
0x0804835d <main+6>: and $0xfffffff0,%esp
0x08048360 <main+9>: mov $0x0,%eax
0x08048365 <main+14>: sub %eax,%esp
0x08048367 <main+16>: movl $0x4,0xc(%esp)
0x0804836f <main+24>: movl $0x3,0x8(%esp)
0x08048377 <main+32>: movl $0x2,0x4(%esp)
0x0804837f <main+40>: movl $0x1,(%esp)
0x08048386 <main+47>: call 0x8048344 <test_function>
0x0804838b <main+52>: leave
0x0804838c <main+53>: ret
End of assembler dump.
(gdb) disass test_function()
You can't do that without a process to debug.
(gdb)
Do you have an idea for the reason of the error? I have already used google but I can't find anything to solve the problem. I also searched for the instructions to be sure that the syntax is right.
http://visualgdb.com/gdbreference/commands/disassemble
Thanks for reading,
Intersect!
The syntax (of the gdb command) is disass function-name so you should type
disass test_function
Read the genuine GDB documentation.
But you typed wrongly disass test_function() ; then ending parenthesis are wrong.
Be sure that you compiled your source code with gcc -Wall -g
At last, you could ask gcc to output an assembler file. Try for instance to compile your source.c file with
gcc -O1 -S -fverbose-asm source.c
(you could omit the -O1 or replace it with -g if you wanted to)
then look with an editor (or some pager) into the generated source.s assembly file.
Maybe the function isn't there because it was inlined during compilation. I had never seen your error message before, sorry.
Please try to compile with the following additional flags:
-O0 -g
You can also see all function start addresses with:
objdump -x <filename>
This gives you a list of symbols in your executable file which includes all the start points of functions.
You can also disassemble your code with:
objdump -d <filename>

Why simple exit program do not work?

I am new to assembly language programming. I write following code,
.text
.globl _start
_start:
movl $1,%eax
movl $0,%ebx
int $0x80
and use as -o JustExit.o JustExit.asm command for creating object file. (Assembly file name is JustExit.asm).
After this step I gave executable permission using,
chmod 777 ./JustExit.o
When I execute program it says,
-su: ./JustExit.o: cannot execute binary file
I am not able to understand why this simple 'exit' program is not working.
Thanks.
Assembling your source through as produces an object file which is "not yet" executable.
You have to link the object file with a linker such as ld, which will then produce a fully working executable (a.out by default).
Your command line chain would look like this:
$ as -o JustExit.o JustExit.asm
$ ld JustExit.o
$ ./a.out
And it works!

Resources