are there debugging options for ld - debugging

I have written an assembly program that, for testing purposes, just exits. The code is as follows:
section .text
_global start
_start:
mov eax, 1
mov ebx, 0
int 0x80
The program is obviously in 32-bit; however, I am using 1 64-bit processor and operating system, so I compiled it (using nasm) and linked it as follows:
nasm -f elf exit.asm
ld -m elf_i386 -s -o exit exit.o
debugging the program with gdb, I can't list the code since there are no debugging symbols.
(gdb) list
No symbol table is loaded. Use the "file" command.
In using gcc, you can use the options -ggdb to load the symbols while compiling a c file. but since I don't how to use gcc to compile 32-bit assembly for 64-bit machines (I have searched this but can't find a solution,) I am forced to use ld. can I load the debugging symbols using ld? sorry for the long question and the excess information. Thanks in advance.

Debugging information is generated by nasm when you pass -g. Additionally, you also need to specify what type of debugging information you want (typically dwarf), which is done with the -F switch. So to assemble your file, write
nasm -f elf -F dwarf -g file.asm
then link without -s to preserve the symbol table and debugging information:
ld -m elf_i386 -o file file.o

The -s switch tells ld to "strip" the debugging info. Lose that!

Related

Windows x86 assembly entry point is wrong

I wrote a test program for learning purposes in x86 assembly using NASM as assembler and MinGW32 (ld) as linkerW.
I am working on Windows 10.
section .text
global my_start
my_start:
nop
nop
nop
nop
jmp my_start
I am using the following command for assembling:
nasm -f win32 -l main.lst main.asm
And the following command for linking:
ld -nostdlib -nostartfiles -s -o main.exe -e my_start main.obj
Now if I run the program I get an sgmentation fault error.
To find out why I used GDB for debugging and found out that windows is executing my executable at file begin where the DOS Header is laying.
So windows is trying to execute the magic number "MZ" (4d 5a) and following bytes as assembler instructions.
So, now I am very confused why this happens because I specified an entry point (-e my_start) followed by valid x86 assembler instructions.
Why exactly my executable start's execute at DOS header and not at my specified entry point in my code segment?
How I can fix this?
EDIT:
I tried now GoLink and using this linker everything is working fine:
GoLink.exe main.obj /entry my_start
I also compared the entry point of the optional header and both are equal.
But comparing both files a lot of things are different so I cannot tell what exactly is wrong so I will stick with GoLink for a while and maybe come back to this problem if I have a bit more experience.

NASM debug symbols for Windows?

I am trying to learn x86 assembly on Windows. I can assemble and link a program successfully using:
nasm -f win32 -g sandbox.asm -l sandbox.lst
ld -mi386pe -o sandbox.exe sandbox.obj
But when I try running my program with gdb, it says that it can't find the debug symbols. Nasm says that only the "null" debug symbol format is available for win32. Does this mean that it can't generate debug symbols for windows? If so, then how can I debug my program on windows?
Here is the example program that I am using:
section .data
section .bss
section .text
global start
start:
mov ebp, esp
mov eax, 0
ret
You must specify the debugging format to include in your binary (sometimes there is not one by default)
try -gcv8 instead of -g

ld MinGW link to standard C library

I have a problem with following code.
extern printf
global _main
main:
push msg
call printf
ret
msg db "Hello world",0
I assemble this with NASM using nasm -fwin32 test.asm Then i link it using ld test.obj.
And it tells me "test.obj:test.asm:(text+0x6): undefined reference to 'printf'"
How to link my file to standard C libraries? I have ld from latest MinGW.
To assemble code :
nasm -fwin32 test.asm
Microsoft will prefix functions using the cdecl calling convention with a underscore.
To be match to the C calling convention printf should be _printf.
The same applies for _main instead of main.
And link with:
ld test.obj -lmsvcrt -entry=_main -subsystem=console -o test.exe
Here -entry command line option is used to invoking ld to specify the entry point for program .
Then use -l options to pass msvcrt library to the ld linker, otherwise you will get an error message, (undefined reference to `printf') which means that the linker did not found the symbol printf in the specified object file produced by NASM.
Here is completed source:
global _main
extern _printf
section .text
_main:
push msg
call _printf
add esp, 4 ;adjust the stack
ret
msg db "Hello world",0
I can see several issues with your code. First, you've got an underscore on global _main but not on main:. These should match. You can either use underscores throughout, or - what I would do - not at all... and for Windows, assemble as nasm -f win32 --prefix _ test.asm. This would make it "portable" in that, for Linux, it would assemble, without the --prefix _ without the underscores. Linux doesn't use underscores on global or extern symbols. If, by some chance, you were using OpenWatcom C, you could use --postfix _. Yeah, OpenWatcom uses trailing underscores. Yeah, I know they told us C was standardized. but once you get under the hood, this isn't really true.
The other big issue is that after calling _printf, you need to add esp, 4 (or pop a dummy register) to "clean up the stack". If you're using Windows APIs, they use the STDCALL calling convention in which "callee cleans up", so you don't want to do this. Mixing C calls (CDECL calling convention) and Windows APIs might get confusing, but should work.
I think Carl has the right idea with using gcc to link it. There's nothing to "compile", but gcc knows the proper command line to ld. gcc -o test.exe test.obj will probably be enough (maybe add -m32 if the latest MinGW expects to be doing 64-bit code). This will link in some "startup code" which calls _main. This will increase the size of your executable slightly, and you "might" be able to get along without it, but it's easier to just do it.
In Linux, we can use ld directly (the command line is horrid), but ld is looking for _start, not main, as the entrypoint. We can tell ld -e main, but this entrypoint is not called(!) and there's no possible way to ret from it! The situation is probably different in Windows. You would need - as a bare minimum - -lc to tell ld that we want those C libraries. Easiest to "let gcc do it" - it won't touch your .asm code (but does link in that "startup code"). Happy Hello World! :)
Use a compiler front-end to link:
cc test.obj
If you really want to use ld directly (and you shouldn't), use the -v flag to cc to figure out what complete command line you need. For example, on my machine, it's:
ld -demangle -dynamic -arch x86_64 -macosx_version_min 10.8.0 \
-o a.out test.obj -lSystem \
/usr/bin/../lib/clang/4.2/lib/darwin/libclang_rt.osx.a
If I use GCC instead of Clang, it's even crazier:
ld -dynamic -arch x86_64 -macosx_version_min 10.8.4 -weak_reference_mismatches \
non-weak -o a.out -lcrt1.10.6.o \
-L/usr/llvm-gcc-4.2/bin/../lib/gcc/i686-apple-darwin11/4.2.1/x86_64 \
-L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/x86_64 \
-L/usr/llvm-gcc-4.2/bin/../lib/gcc/i686-apple-darwin11/4.2.1 \
-L/usr/llvm-gcc-4.2/bin/../lib/gcc \
-L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1 \
-L/usr/llvm-gcc-4.2/bin/../lib/gcc/i686-apple-darwin11/4.2.1/../../.. \
-L/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/lib/gcc/i686-apple-darwin11/4.2.1/../../.. \
test.obj -lgcc -lSystem

Can't link assembly file in Mac OS X using ld

I'm trying to run a basic assembly file using 64 Bit Mac OS X Lion, using nasm and ld which are installed by default with Xcode.
I've written an assembly file, which prints a character, and I got it to build using nasm.
nasm -f elf -o program.o main.asm
However, when I go to link it with ld, it fails with quite a few errors/warnings:
ld -o program program.o
ld: warning: -arch not specified
ld: warning: -macosx_version_min not specificed, assuming 10.7
ld: warning: ignoring file program.o, file was built for unsupported file format which is not the architecture being linked (x86_64)
ld: warning: symbol dyld_stub_binder not found, normally in libSystem.dylib
ld: entry point (start) undefined. Usually in crt1.o for inferred architecture x86_64
So, I tried to rectify a few of these issues, and got nowhere.
Here's one of things I've tried:
ld -arch i386 -e _start -o program program.o
Which I thought would work, but I was wrong.
How do you make the object file a compatible architecture that nasm and ld will agree with?
Also, how would you define the entry point in the program (right now I'm using global _start in .section text, which is above _start, which doesn't seem to do much good.)
I'm a bit confused as to how you would successfully link an object file to a binary file using ld, and I think I'm just missing some code (or argument to nasm or ld) that will make them agree.
Any help appreciated.
You need to use global start and start:, no underscore. Also, you should not be using elf as the arch. Here is a bash script I use to assemble my x86-64 NASM programs on Mac OS X:
#!/bin/bash
if [[ -n "$1" && -f "$1" ]]; then
filename="$1"
base="${filename%%.*}"
ext="${filename##*.}"
nasm -f macho64 -Ox "$filename" \
&& ld -macosx_version_min 10.7 "${base}.o" -o "$base"
fi
If you have a file called foo.s, this script will first run
nasm -f macho64 -Ox foo.s
Which will create foo.o. The -Ox flag makes NASM do some extra optimization with jumps (i.e. making them short, near or far) so that you don't have to do it yourself. I'm using x86-64, so my code is 64-bit, but it looks like you're trying to assemble 32-bit. In that case, you would use -f macho32. See nasm -hf for a list of valid output formats.
Now, the object file will be linked:
ld -macosx_version_min 10.7 foo.o -o foo
I've set the -macosx_version_min option to quiet NASM down and prevent a warning. You don't have to set it to Lion (10.7). This will create an executable called foo. With any luck, typing ./foo and hitting return should run your program.
In regard to the ld: warning: symbol dyld_stub_binder not found, normally in libSystem.dylib warning, I get that every time too and I'm not sure why, but everything seems fine when I run the executable.
OK, looking at your samples I assume you either used a generic nasm or linux assembly tutorial.
The first thing you need to take care of is the binary format created by nasm.
Your post states:
ld: warning: ignoring file program.o, file was built for unsupported file format which is not the architecture being linked (x86_64)
Thats the result of the '-f elf' parameter which tells nasm you want a 32bit ELF object (which would be the case for e.g. linux). But since you're on OSX what you want is a Mach-O object.
Try the following:
nasm -f macho64 -o program.o main.asm
gcc -o program program.o
Or if you wan't to create a 32bit binary:
nasm -f macho32 -o program.o main.asm
gcc -m32 -o program program.o
Regarding the _start symbol - if you wan't to create a simple program that will be able
to use the provided libc system functions then you shouldn't use _start at al.
It's the default entry point ld will look for and normaly it's provided in your libc / libsystem.
I suggest you try to replace the _start in your code by something like '_main'
and link it like the example above states.
A generic libc-based assembly template for nasm could look like this:
;---------------------------------------------------
.section text
;---------------------------------------------------
use32 ; use64 if you create 64bit code
global _main ; export the symbol so ld can find it
_main:
push ebp
mov ebp, esp ; create a basic stack frame
[your code here]
pop ebp ; restore original stack
mov eax, 0 ; store the return code for main in eax
ret ; exit the program
In addition to this I should mention that any call's you do on OSX need to use an aligned stack frame or your code will just crash.
There are some good tutorials on that out there too - try searching for OSX assembly guide.
It's probably easier just to let gcc do the heavy lifting for you, rather than trying to drive ld directly, e.g.
$ gcc -m32 program.o -o program
The mac gcc compiler won't link elf objects. You need a cross compiler...
http://crossgcc.rts-software.org/doku.php?id=compiling_for_linux
Then you can proceed with something similar to this...
/usr/local/gcc-4.8.1-for-linux32/bin/i586-pc-linux-ld -m elf_i386 -T link.ld -o kernel kasm.o kc.o

Details on gdb memory access complaint

I have an object file compiled using as (from assembler code).
If I link it using ld, when I try to stepi (or nexti) gdb complains about memory access at address 0x0. If I link it using gcc, all is fine.
I am guessing the problem is caused by ld, which produces fewer sections when compared to the linking result of gcc.
Is there a way to configure gdb to be more verbose so I can maybe figure out what's wrong with the executable?
(gdb) b main
Breakpoint 1 at 0x100000f8e
(gdb) r
Breakpoint 1, 0x0000000100000f8e in main ()
(gdb) x/10i $pc
0x100000f8e <main>: fbld 0x6c(%rip) # 0x100001000 <data1>
0x100000f94 <main+6>: fimul 0x7a(%rip) # 0x100001014 <data2>
0x100000f9a <main+12>: fbstp 0x60(%rip) # 0x100001000 <data1>
0x100000fa0 <main+18>: mov0x0 $0x2000001,%rax
0x100000fa7 <main+25>: mov $,%rdi
0x100000fae <main+32>: syscall
(gdb) si
Cannot access memory at address 0x0
0x0000000100000f94 in main ()
PS: The executable itself runs as expected in both versions.
Later edit: commands i've used to compile:
as -arch x86_64 src.s -o src.o
ld -e _main -arch x86_64 src.o -o src
gcc -o src src.o
gdb has a "show debug" command, giving various internal debug settings. E.g. "set debug target 1" will turn on tracing for gdb's interaction with the target process. You might want to experiment with every flag they have (there aren't that many).
GCC doesn't actually do the linking, it just calls ld on your behalf. The options it's providing must be different from the ones you are using.
Per this thread:
How to get GCC linker command?
You should be able to see the ld invocation's command line by running gcc -v.
That should tell you how to modify your ld command line so things work for you.

Resources