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>
Related
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
I have a shellcode file.
Then use ndisasm to build the assembly code.
ndisasm -b 64 shellcode > shellcode.asm
cat shellcode.asm | cut -c29->key.asm
I add 2 lines to the key.asm file
global_start:
_start:
$vi key.asm
global_start:
_start:
xor eax,eax
push rax
push qword 0x79237771
push qword 0x76772427
push qword 0x25747320
. . .
. . .
. . .
push qword 0x20757577
push rsp
pop rsi
mov edi,esi
mov edx,edi
cld
mov ecx,0x80
mov ebx,0x41
xor eax,eax
push rax
lodsb
xor eax,ebx
An then I assemble and link it to 64 bit executables
$nasm -f elf64 -g -F stabs key.asm
$ld -o key key.o
It gives me a warning
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400080
I tested it out with gcc
gcc -o key key.o
I still get an error almost the same as the first one
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o: In
function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
And when I run ./key with gdb after I use $ld NOT $gcc
$gdb -q ./key
$run
I get a seg fault
Starting program: /mnt/c/Users/owner/Documents/U
M/Computer_Security/ExtraCredit/key
Program received signal SIGSEGV, Segmentation fault.
0x000000000040013a in global_start ()
If I debug after run with gcc then the file will not be found because of exit status
Can you explain why does it happen? And how can I fix this problem? Thanks
It gives me a warning
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400080
This isn't actually a problem, as long as you're fine with the entry point being the start of the text segment (i.e. the first instruction in your shellcode).
You got the error because you left out the space between the global keyword and the _start symbol name. i.e. use global _start, or don't bother. What you did defined a label called global_start, as you can see from your later error message.
You segfault on lodsb because you truncated a stack address with mov edi,esi instead of mov rdi, rsi. And if you fix that then you fall off the end of your code into garbage instructions because you don't make an exit system call. You're already running this inside gdb, use it!
I tested it out with gcc: gcc -o key key.o
I still get an error almost the same as the first one
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o:
In function `_start':
(.text+0x20): undefined reference to `main'
No, that's a totally different error. If you had exported _start correctly, you would have gotten an error for conflicting definitions of _start (between your code and the CRT start files).
This error is that the _start definition in crt1.o (provided by gcc) has a reference to main, but your code doesn't provide a main. This is what happens when you try to compile a C or C++ program that doesn't define main.
To link with gcc, use -nostdlib to omit the CRT start files and all other libraries. (i.e. link pretty much exactly like you were doing manually with ld.)
gcc -nostdlib -static key.o -o key # static executable: just your code
Or dynamically linked without the CRT start files, using your _start.
gcc -nostdinc -no-pie key.o -o key
You can call libc functions from code linked that way, but only on Linux or other platforms where dynamic linking takes care of running libc initialization functions.
If you statically link libc, you can only call functions like printf if you first call all the libc init functions that the normal CRT startup code does. (Not going into detail here because this code doesn't use libc)
Your code is wrong. Between global and _start must have a space. That is one of your problems.
section .text
global _start
_start:
xor eax,eax
push rax
...
In addition, to get why the segmentation fault is happening, you have to debug it. You could look the assembly instruction that does the segfault.
x/5i $eip
I'm writing assembly language, program like this:
.data
.equ b,3
.text
.globl _start
_start:
movl $2,%ebx
movl $b,%ecx
movl $1,%eax
int $0x80
I compile it under ubuntu 64bit version. I wish to get a 32bit version, so under shell I can do:
$ as my.s -32
$ ld a.out -o my
OK, no problem. I wish to use scons to manage this process, so I have SConstruct:
Program('my.s')
This will first compile using 'as my.s -o my.o' and 'gcc my.o -o my', and report and error of redefinition of '_start'.
My problem is:
How can I pass '-32' option to make sure I compile out 32bit version object file?
How can I specify the linker to be 'ld' but not 'gcc', to make sure I can use '_start' as entry point in my assembly source file?
For passing flags to the assembler, ASFLAGS should work.
For passing flags to linker, LINKFLAGS should work
For setting which executable to use for linker, LINK (or SHLINK) should do the trick.
All these are listed in the manpage: http://scons.org/doc/production/HTML/scons-man.html
Likely the following should work for you:
env=Environment(tools=['as','gnulink'])
env['ASFLAGS'] = '-32'
env['LINK'] = 'ld'
env.Program('my',['my.s'])
I'm learning assembly with NASM for a class I have in college. I would like to link the C Runtime Library with ld, but I just can't seem to wrap my head around it. I have a 64 bit machine with Linux Mint installed.
The reason I'm confused is that -- to my knowledge -- instead of linking the C runtime, gcc copies the things that you need into your program. I might be wrong though, so don't hesitate to correct me on this, please.
What I did up to this point is, to link it using gcc. That produces a mess of a machine code that I'm unable to follow though, even for a small program like swapping rax with rbx, which isn't that great for learning purposes. (Please note that the program works.)
I'm not sure if it's relevant, but these are the commands that I'm using to compile and link:
# compilation
nasm -f elf64 swap.asm
# gcc
gcc -o swap swap.o
# ld, no c runtime
ld -s -o swap swap.o
Thank you in advance!
Conclusion:
Now that I have a proper answer to the question, here are a few things that I would like to mention. Linking glibc dynamically can be done like in Z boson's answer (for 64 bit systems). If you would like to do it statically, do follow this link (that I'm re-posting from Z boson's answer).
Here's an article that Jester posted, about how programs start in linux.
To see what gcc does to link your .o-s, try this command out: gcc -v -o swap swap.o. Note that 'v' stands for 'verbose'.
Also, you should read this if you are interested in 64 bit assembly.
Thank you for your answers and helpful insight! End of speech.
Here is an example which uses libc without using GCC.
extern printf
extern _exit
section .data
hello: db 'Hello world!',10
section .text
global _start
_start:
xor eax, eax
mov edi, hello
call printf
mov rax, 0
jmp _exit
Compile and link like this:
nasm -f elf64 hello.asm
ld hello.o -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc -m elf_x86_64
This has worked fine so far for me but for static linkage it's complicated.
If you want to call simple library functions like atoi, but still avoid using the C runtime, you can do that. (i.e. you write _start, rather than just writing a main that gets called after a bunch of boiler-plate code runs.)
gcc -o swap -nostartfiles swap.o
As people say in comments, some parts of glibc depend on constructors/destructors run from the standard startup files. Probably this is the case for stdio (puts/printf/scanf/getchar), and maybe malloc. A lot of functions are "pure" functions that just process the input they're given, though. sprintf/sscanf might be ok to use.
For example:
$ cat >exit64.asm <<EOF
section .text
extern exit
global _start
_start:
xor edi, edi
jmp exit ; doesn't return, so optimize like a tail-call
;; or make the syscall directly, if the jmp is commented
mov eax, 231 ; exit(0)
syscall
; movl eax, 1 ; 32bit call
; int 0x80
EOF
$ yasm -felf64 exit64.asm && gcc -nostartfiles exit64.o -o exit64-dynamic
$ nm exit64-dynamic
0000000000601020 D __bss_start
0000000000600ec0 d _DYNAMIC
0000000000601020 D _edata
0000000000601020 D _end
U exit##GLIBC_2.2.5
0000000000601000 d _GLOBAL_OFFSET_TABLE_
00000000004002d0 T _start
$ ltrace ./exit64-dynamic
enable_breakpoint pid=11334, addr=0x1, symbol=(null): Input/output error
exit(0 <no return ...>
+++ exited (status 0) +++
$ strace ... # shows the usual system calls by the runtime dynamic linker
I was searching other threads without luck.
My problem is perhaps simple but frustrating.
I'm compiling two files on 64-bit Ubuntu 11.04:
nasm -f elf64 -g file64.asm
gcc -g -o file file.c file64.o
Then I debug the resulting executables with gdb.
With C, everything is OK.
However, when debugging assembly, the source code is "not visible" to the debugger. I'm getting the following output:
(gdb) step
Single stepping until exit from function line,
which has no line number information.
0x0000000000400962 in convert ()
A quick investigation with:
objdump --source file64.o
shows that the assembly source code (and line information) is contained in the file.
Why can't I see it in a debug session? What am I doing wrong?
These problems arose after moving to 64-bit Ubuntu. In the 32-bit Linux it worked (as it should).
With NASM, I've had much better experience in gdb when using the dwarf debugging format. gdb then treats the assembly source as if it were any other language (i.e., no disassemble commands necessary)
nasm -f elf64 -g -F dwarf file64.asm
(Versions 2.03.01 and later automatically enable -g if -F is specified.)
I'm using NASM version 2.10.07. I'm not sure if that makes a difference or not.
GDB is a source-level (or symbolic) debugger, which means that it's supposed to work with 'high-level programming languages' ... which is not you're case!
But wait a second, because, from a debugger's point of view, debugging ASM programs is way easier than higher level languages: there's almost nothing to do! The program binary always contains the assembly instruction, there're just written in their machine format, instead of ascii format.
And GDB has the ability to convert it for you. Instead of executing list to see the code, use disassemble to see a function code:
(gdb) disassemble <your symbol>
Dump of assembler code for function <your symbol>:
0x000000000040051e <+0>: push %rbp
0x000000000040051f <+1>: mov %rsp,%rbp
=> 0x0000000000400522 <+4>: mov 0x20042f(%rip),%rax
0x0000000000400529 <+11>: mov %rax,%rdx
0x000000000040052c <+14>: mov $0x400678,%eax
0x0000000000400531 <+19>: mov %rdx,%rcx
or x/5i $pc to see 5 i nstruction after your $pc
(gdb) x/5i $pc
=> 0x400522 <main+4>: mov 0x20042f(%rip),%rax
0x400529 <main+11>: mov %rax,%rdx
0x40052c <main+14>: mov $0x400678,%eax
0x400531 <main+19>: mov %rdx,%rcx
0x400534 <main+22>: mov $0xc,%edx
then use stepi (si) instread of step and nexti (ni) instead of next.
display $pc could also be useful to print the current pc whenever the inferior stops (ie, after each nexti/stepi.
For anyone else stuck with the broken things on NASM (the bug is not fixed so far): just download the NASM git repository and switch to version 2.7, which is probably the last version that works fine, i.e. supports gdb. Building from source this outdated version is only a workaround (you don't have support for the last ISA for example), but it's sufficient for most students.
GDB might not know where to search for your source files. Try to explicitly tell it with directory.