GDB an ELF File Under Win32 - debugging

I wanted to study ELF relocation mechanism, so I assembled an x86 assembly program using NASM to produce an ELF file, but under Win32. Then I used mingw32's gdb to debug it. It loaded nicely and I could view the program using "list" command. However, I couldn't run it. I got the following messages:
Starting program: c:\Projects\NasmProjects\Test01\Hello.o
Error creating process c:\Projects\NasmProjects\Test01\Hello.o
Is there a way around this?

Is there a way around this?
No.
First, you have assembled a relocatable object file (of type ET_REL). There is no OS that will "run" such files -- OSes that do support executing ELF files, require a fully linked executable (of type ET_EXEC or ET_DYN).
Second, even if you manage to link an ET_EXEC, you still need your OS to know how to load and start executing such a file. Linux and Solaris kernels do know this, AIX and Windows kernels do not.

Related

Cross-compiling for a specific platform -- linking libc

I have to compile a simple binary for a very old Linux system. I have no gcc/build libs available on the target machine but I do have access to the machine.
I am having trouble compiling the code on my machine and having it execute on target machine.
I am copying libc.so to my local machine and trying to compile and link the program so that it will execute on the target machine.
I have copied the libc from the target machine to mine and tried compiling it with my target executable.
this has gotten closes to a successful execution:
gcc -nostdlib ./libc-[version].so myFile.c -emain -o outfile.out
upon execution a very simple PoC test program runs, and then seg faults upon exit. the actual program simply seg faults.
It seems I have somewhat of a lack of understanding of linking. Any help?
It seems I have somewhat of a lack of understanding of linking.
You do. A "normal" user-level program doesn't start executing at main, it starts at _start.
The _start symbol typically comes from crt0.o file (part of libc), and knows how to "interface" between the way the kernel supplies arguments, and the way main expects to find them. It also initializes various data that must be initialized before main runs (e.g. stdio streams).
What you want to do then is:
Find out the actual link command that gcc main.o performs. You can do so by adding the -v flag.
Replicate such command, providing crt0.o and other input files, appropriate for your version of target libc.
It might be easier to spin up a VM with the OS matching your target (and with old tools that target it), and build your program inside of that VM.
Otherwise you'll likely have to set up a full cross-compiler environment (which includes libc and all other libraries you need). This is not a trivial proposition, and is certainly not accomplished by copying libc.so from the target machine. But it is well-documented and is certainly doable (with some skill).

Add breakpoints to elf

I am building an OS in assembly and I am using NASM for assembly. I am telling to NASM to create a binary file that I am using to debug with QEMU.
To debug easier I am using gdb with QEMU. I am giving to gdb an .elf object file that I am creating using NASM (with the same input files and just .elf output).
The NASM does not support adding breakpoints in source code and when I want to put a breakpoint I am telling it to gdb. Because I am assembling a lot of times per day the OS using a batch file. The problem is that evry time I am reassembling the OS the debug info are lost so I need to reput the breakpoints.
As you may know an OS have a lot of functions and I want to put a breakpoint at most of them so I cannot continue with this way.
So which the way to put breakpoints at an elf file?
I can for example use the gdb and at command line pass a file as stdin that contains the instructions and then exit?

Booting custom kernel on xeon-phi

I am trying to boot a custom kernel on Xeon-phi instead of the default Linux kernel. At this link, I found a way to cross compile my kernel which compiles successfully using k1om-mpss-linux-gcc cross compiler. Is cross compiling enough ? I get the error
mykernel.img is not a k1om Linux bzImage
Edit:
So, I used /usr/linux-k1om-4.7/bin/x86_64-k1om-linux-gcc compiler to compile a simple helloworld.c program and the kernel source. I get two different types of results for objdump -f on the executables.
for helloworld.c:
hello: file format elf64-k1om
architecture: k1om, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x0000000000400400
for mykernel:
mykernel: file format elf32-i386
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x0010000c
I compiled using the same compiler, yet they show different architectures. What is the reason for this ?
The first thing to do is figure out what mykernel.img is. Try running file on it.
$ file /opt/mpss/3.4/sysroots/k1om-mpss-linux/boot/vmlinux-2.6.38.8+mpss3.4
/opt/mpss/3.4/sysroots/k1om-mpss-linux/boot/vmlinux-2.6.38.8+mpss3.4: ELF 64-bit LSB executable, version 1 (SYSV), statically linked, BuildID[sha1]=0xa4c16ee85c11aca4e78dc4ae46d3827fb74289c1, not stripped
$ objdump -f /opt/mpss/3.4/sysroots/k1om-mpss-linux/boot/vmlinux-2.6.38.8+mpss3.4
/opt/mpss/3.4/sysroots/k1om-mpss-linux/boot/vmlinux-2.6.38.8+mpss3.4: file format elf64-k1om
architecture: k1om, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x0000000001000000
The answer to your original question - no, unfortunately, it is not as simple as just cross-compiling. There were a number of changes made to the kernel that comes with the MPSS. I don't know all the changes but a big one that I do know is that they had to add support for the larger register set on the coprocessor in order to be able to save state on a context switch.
As to why the file format is elf32-i386 instead of elf32-k1om -
The web site you referenced referred to recompiling the kernel that came with the MPSS after possibly make a few changes in the files. You'll notice that they also copied over a configuration file for the installed version of the kernel. So they had all the files to remake the kernel exactly as it had been made.
I suspect that, in your case, either a) there was a configuration script of some sort in your source directory that picked up the architecture you were running on and caused confusion when the makefile ran or b) your makefile had no idea what k1om was. In either case, it fell back to what it believed to the the lowest common denominator i386. As I say, this is just a suspicion on my part but a careful reading of your makefiles should lead to the answer.

seg fault when running arm-elf-gcc compiled code

Using MacPorts i have just installed arm-elf-gcc on to my MacBook Pro. This worked flawlessly and all seems to run fine.
However, after compiling a simple hello world test program in C and C++ and trying to run either on the target board (an ARM9 based board running Debian Linux) they immediately seg fault.
I'm a bit stuck as how to go about debugging this, as the target board has limited tools available and no gdb. I have successfully built and run other code using a Linux hosted cross compiler so it should work.
Any ideas?
Following the suggestion I have built and run gdbserver, I get the following in gdb on the host:
Program received signal SIGSEGV, Segmentation fault.
0x00000000 in ?? ()
I thought it may be a problem with the standard c libs so I removed any calls and have just an empty main that return 0, it is compiled with -Wall -g hello-arm.cpp -static. As a test I compiled the same source with a Linux hosted cross compiler and it runs and exits fine. The only difference I can see is the that Linux compiled version is over twice the size and the difference in output from the file command:
arm-elf-gcc: ELF 32-bit LSB executable, ARM, version 1, statically linked, not stripped
arm-*-linux: ELF 32-bit LSB executable, ARM, version 1, statically linked, for GNU/Linux 2.4.18, not stripped
The usual method of debugging in this situation is to run gdbserver on the target board, and connect to it (via ethernet) with gdb running on a host computer.
Alternately, you could try comparing the assembly in a Mac-compiled "Hello World" program and a (working) Linux-compiled one to see what's different.
After digging around for a couple of days I am starting to understand a bit more about embedded compilers. I wasn't really sure of the difference between arm-elf-gcc installed via MacPorts and the arm-unknown-linux toolchain I had installed on my Linux box. I just came across a pdf titled "An introduction to the GNU compiler" which contains the following paragraph:
Important: Using the GNU Compiler to
create your executable is not quite
the same as using the GNU Linker,
arm-elf-ld, yourself. The reason is
that the GNU Compiler automatically
links a number of standard system
libraries into your executable. These
libraries allow your program to
interact with an operating system, to
use the standard C library functions,
to use certain language features and
operations (such as division), and so
on. If you wish to see exactly which
libraries are being linked into the
executable, you should pass the
verbose flag
-v to the compiler.
This has important implications for
embedded systems! Such systems do not
usually have an operating system.
This means that linking in the system
libraries is almost always
meaningless: if there is no operating
system, for example, then calling the
standard printf function does not make
much sense.
So when I get back to my dev machine later I will determine the libraries linked in with the Linux build and add them to the arm-elf-gcc build.
I'll update this when I have more information but I just want to document my findings in case any one else has these problems.

How do I do source level debug of library

I have a following setup. Although my working setup deals with ARM compiler Real View Developer Suite (RVDS) 3.2 on a Windows host, the situation could be generic for any other C compiler on any host.
I build a ARM library (static library - .a file) of C code using RVDS 3.2 compiler toolchain on Windows host. Then I link this library with an application using an ARM-Linux compiler toolchain on a Linux host, to get a ARM executable. Now when I try to debug this generated ARM executable on Linux using gdb, by trying to put a breakpoint in some function which is present in the library that is linked, gdb is not able to put breakpoint there citing source not found. So I manually copied all the source files(*.c) used to create the library in the Linux folder where the executable file is present. Still gdb fails to put a breakpoint.
So now I started thinking:
How can I do source level debugging of this library which I create on Windows using a different compiler chain by launching the executable which is generated by linking this library to an application, in gdb. Is it possible? How can I do it? Is there any compiler option in RVDS compiler toolchain to enable this library source level debug?
Do I need to copy the source files to linux in exactly same folder structure as that is present in windows for those source files?
You could try to see if mimicking the exact same directory structure works. If you're not sure what directory structure the compiler annotated in the debug info in the executable, you can always look at it with dwarfdump (on linux).
First, GDB does not need any source to put breakpoints on functions; so your description of what is actually happening is probably inaccurate. I would start by verifying that the function you want to break on is actually there in the binary:
nm /path/to/app | grep function_desired
Second, to do source level debugging, GDB needs debug info in a format GDB understands. On Linux this generally means DWARF or STABS. It is quite possible that your RVDS compiler does not emit such debug info; if so, source level debugging will not be possible.
Did you build the library with debugging enabled (-g option)? Without that, there would be difficulties identifying lines etc.
I've found that -fPIC will cause this sort of issue, but the only work around I've found is to not use -fPIC when I want to debug.

Resources