Bare-metal hello world PPC64 (QEMU + OFW) not working - powerpc

I'm new to bare-metal and kernel programming, and what better way to start my journey than with a hello world!
Sadly, when it comes to my architecture of choice, PPC64 (Using QEMU and OpenFirmware), I struggle to find relevant information or code examples on how to make a hello world program, using the firmware.
So far I've struggled to get the most simple things working, so far I've tried using this start as my main function and this linker script:
.section .boot, "aw"
.global start
start:
b start # Basically halt the machine.
ENTRY(start)
SECTIONS
{
. = 1M;
.text : {
*(.boot)
*(.text*)
}
.data : {
*(.data*)
*(.rodata*)
}
.bss : {
*(COMMON)
*(.bss)
}
}
I've tested it with:
clang --target=ppc64-unknown-elf -c <asm_file> -o <asm_file>.o
ld.lld --oformat elf_ppc64 --nostdlib -T <linkscript> <asm_file>.o -o output.elf
qemu-system-ppc64 -kernel output.elf -serial stdio
But so far the only outcome of my attempts has been this output of SLOF in QEMU emulation:
Detected RAM kernel at 400000 (4 bytes)
Welcome to Open Firmware
Copyright (c) 2004, 2017 IBM Corporation All rights reserved.
This program and the accompanying materials are made available
under the terms of the BSD License available at
http://www.opensource.org/licenses/bsd-license.php
Booting from memory...
( 700 ) Program Exception [ 1dbf04c4 ]
R0 .. R7 R8 .. R15 R16 .. R23 R24 .. R31
8000000000002000 000000001e478200 0000000000000000 0000000000000000
000000001dc71000 8000000000000000 0000000000000000 0000000000000000
0000000000000000 000000001e477010 0000000000000000 0000000000000000
0000000000000000 0000000000000030 0000000000000000 0000000000000000
0000000000000000 000000000000005b 0000000000000000 0000000000000000
000000001dbf04c4 0000000000000000 0000000000000000 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000
How could I get this little snippet to work? Is there any documentation I could use to finish the complete hello world program? Thanks in advance!

Have a look at the micropython powerpc port README here:
https://github.com/micropython/micropython/tree/master/ports/powerpc
It shows you how to run qemu and skip open firmware directly into your test program. You'll want a stripped binary rather than the elf (see the objcopy in the Makefile)
In that directory there is a linker script and a head.S which shows you the basics.
Good luck!

Related

Controlling ELF file size using linker script

I am generating an ELF file for ARM platform using linaro tool chain.
The file is an executable that is supposed to run bare-metal.
I use a linker script to select the locations of sections in the memory because I want to put specific sections in specific locations.
The problem is that when I move some section forward in the memory I see that the image size increases, although no additional data has been added.
When I run readelf -a elf_file I see that both the virtual address (see Address field below) and the offset in image (See Offset field below) are both increased.
Example:
The following lines in the linker script
. = 0x2000000;
.__translations_block_0 : { TM_TranslationTables.o(__translations_block_0) }
Result in the following offsets in the elf file (output from readelf)
[Nr] Name Type Address Offset Size EntSize Flags Link Info Align
[10] .tdata PROGBITS 0000000000279000 00279080 000000000000000c 0000000000000000 WAT 0 0 16
[11] .tbss NOBITS 0000000000279080 0027908c 0000000000011bcc 0000000000000000 WAT 0 0 16
[12] .__translations_b PROGBITS 0000000002000000 02000080 0000000000000008 0000000000000000 WA 0 0 8
[13] .__translations_b PROGBITS 0000000002001000 02001080 0000000000000008 0000000000000000 WA 0 0 8
My question is:
Is there a way to increase the address of some section without blowing the image size? I just want the section to be loaded into memory address 0x2000000, I don't want the image size to be 0x2000000.
Any help would be appreciated.

undefined reference to `__imp___gmpz_init', building GMP program on Cygwin

I'm trying to compile this simple GMP program on Cygwin:
#include <gmp.h>
int main(){
mpz_t i;
mpz_init(i);
}
This is the command:
gcc -lgmp test.c
I get this error:
/tmp/ccJpGa7K.o:test.c:(.text+0x17): undefined reference to `__imp___gmpz_init'
/tmp/ccJpGa7K.o:test.c:(.text+0x17): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `__imp___gmpz_init'
collect2: error: ld returned 1 exit status
Any idea what's wrong? I know it can find the library (libgmp.dll.a), but it doesn't seem to find the function.
Output of nm /usr/lib/libgmp.dll.a | grep mpz_init:
0000000000000000 T __gmpz_inits
0000000000000000 I __imp___gmpz_inits
0000000000000000 T __gmpz_init_set_ui
0000000000000000 I __imp___gmpz_init_set_ui
0000000000000000 T __gmpz_init_set_str
0000000000000000 I __imp___gmpz_init_set_str
0000000000000000 T __gmpz_init_set_si
0000000000000000 I __imp___gmpz_init_set_si
0000000000000000 T __gmpz_init_set_d
0000000000000000 I __imp___gmpz_init_set_d
0000000000000000 T __gmpz_init_set
0000000000000000 I __imp___gmpz_init_set
0000000000000000 T __gmpz_init2
0000000000000000 I __imp___gmpz_init2
0000000000000000 T __gmpz_init
0000000000000000 I __imp___gmpz_init
I tried it without grep and every single symbol in there has address 0 for some reason.
This fixed it: gcc test.c -lgmp. I just put -lgmp last. This seems to be something particular to Cygwin, I tried it with both Clang and gcc-4.9 on OS X and they don't care about the order.
As for the strange behavior with the dll.a file, this is because some *.a files are just stubs that cause linking against the actual cyg*.dll which are all in /usr/bin or /usr/local/bin. However, I think this should always be automatic because Cygwin tries to be POSIX, so if you do it right then you shouldn't have to reference cyg*.dll files.
Found out from here:
https://cygwin.com/ml/cygwin/2011-12/msg00305.html
Using g++ main.c -o main -lgmp worked for me.
Basically, all I had to do was putting the -lgmp in the end.
I also had the same issue while using gmp.h with codeblocks on Windows 7. My solution
1. Install gmp from deval while installing cygwin
2. Add path the path of libgmp.a and libgmp.dll.a in your editor's linker
3. Rebuild all.

Can a linked ELF binary contain multiple .text.* sections (automatically)

I am currently experimenting with GNU LD linker scripts.
I want to have multiple .text.* sections in the compiled & linked Linux x64 ELF binary.
I compiled my sample code into an .o object file via
gcc -ffunction-sections -fdata-sections -c sample.c
and now every function is placed into a separate .text. section in the object file:
<...>
8 .text.main 0000003b 0000000000000000 0000000000000000 00000098 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
9 .text.printString 0000001f 0000000000000000 0000000000000000 000000d3 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
10 .text.addPrintNumbers 00000032 0000000000000000 0000000000000000 000000f2 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
11 .text.getAnotherNumber 0000000b 0000000000000000 0000000000000000 00000124 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
<...>
Linking this with LD and a custom script, leads to all code being merged into one monolithic .text section in the ELF binary.
I tried two variants for .text.* merging:
<...>
.text :
{
KEEP (*(.text .text.*))
KEEP (*(.text.unlikely .text.*_unlikely .text.unlikely.*))
KEEP (*(.text.exit .text.exit.*))
KEEP (*(.text.startup .text.startup.*))
KEEP (*(.text.hot .text.hot.*))
KEEP (*(.stub .gnu.linkonce.t.*))
/* .gnu.warning sections are handled specially by elf32.em. */
KEEP (*(.gnu.warning))
}
<...>
(I know this KEEP arguments is only for the LD garbage collector to keep this section in code, not to place it into a separate section.
When I tried this experimental construct:
<...>
.text.addPrintNumbers :
{
KEEP(*(.text.addPrintNumbers))
}
.text.printString :
{
KEEP(*(.text.printString))
}
.text :
{
KEEP (*(.text .text.*))
KEEP (*(.text.unlikely .text.*_unlikely .text.unlikely.*))
KEEP (*(.text.exit .text.exit.*))
KEEP (*(.text.startup .text.startup.*))
KEEP (*(.text.hot .text.hot.*))
KEEP (*(.stub .gnu.linkonce.t.*))
/* .gnu.warning sections are handled specially by elf32.em. */
KEEP (*(.gnu.warning))
}
<...>
I had some partial success (objdump -x ./sample | less):
<...>
11 .text.addPrintNumbers 00000032 0000000000400400 0000000000400400 00000400 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .text.printString 0000001f 0000000000400432 0000000000400432 00000432 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .text 00000112 0000000000400460 0000000000400460 00000460 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
<...>
And the two manual linked sections where placed in the ELF binary and were still executable.
Is it possible to have all .text.* sections in the compiled and linked binary automatically, without a manual edited LD script.
I am looking for a flag which does automatically, what I managed with the manually edited LD script.
About avoiding a custom linker script, I don't think it is possible. If you want to fiddle with sections you need a linker script.
In my machine, the command ld --verbose outputs:
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
}
If you want to change that, you must change the script. There is no workaround!
Try to turn optimization on. Somehow turning optimization on, e.g. -O2 flag, instructs the compiler and the linker not to merge .text.* sections

missing symbols in valgrind stacktrace

I'm using valgrind to debug a binary which uses loadable libraries via dlopen.
On debian stable the stacktrace does not contain symbols for calls inside the loadable lib.
| | ->11.55% (114,688B) 0x769492C: ???
| | | ->11.55% (114,688B) 0x7697289: ???
| | | ->11.55% (114,688B) 0x769806F: ???
| | | ->11.55% (114,688B) 0x419812: myfunc (main.c:1010)
Valgrind on debian unstable works fine and the symbols are properly resolved. So I started looking what is different.
I have these packages on both systems (valgrind was updated to 3.7 from unstable):
ii valgrind 1:3.7.0-1+b1
ii libtool 2.2.6b-2
ii gcc 4:4.4.5-1
ii binutils 2.20.1-16
The libs are not stripped and contain debuginfo:
ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=0x33ffd210859178c15bb3923c5491e1a1b6065015, not stripped
Looking closer I noticed that the size of the libraries are different, on debian unstable the lib is slightly bigger. Comparing them with readelf, the size of the debug info is bigger.
[26] .debug_aranges PROGBITS 0000000000000000 00a74c 000090 00 0 0 1
[27] .debug_pubnames PROGBITS 0000000000000000 00a7dc 000385 00 0 0 1
[28] .debug_info PROGBITS 0000000000000000 00ab61 00512f 00 0 0 1
[29] .debug_abbrev PROGBITS 0000000000000000 00fc90 0006e2 00 0 0 1
[30] .debug_line PROGBITS 0000000000000000 010372 002314 00 0 0 1
[31] .debug_str PROGBITS 0000000000000000 012686 0019d3 01 MS 0 0 1
[32] .debug_loc PROGBITS 0000000000000000 014059 000f24 00 0 0 1
[33] .debug_macinfo PROGBITS 0000000000000000 014f7d 179082 00 0 0 1
[34] .debug_ranges PROGBITS 0000000000000000 18dfff 000060 00 0 0 1
This makes me think that something is missing from the debug info section from the binaries built on debian stable. Now my question is: why and how are the binaries different? The tools (gcc, libtool, binutils) used in the build are the same, including the compiler/linker flags and commands (I checked with diff on make's output).
Update:
The debug_info section size difference came from the fact that the full path of the source file is stored there as well and the build home was different. Also there are different openssl versions on unstable/stable which added some different symbols to the debug_info section. Hence the difference in debug_info size.
Running valgrind in debug mode (-d -v -v) shows that it reads symbols from the loadable lib in both cases:
--19837-- Reading syms from /usr/lib/myplugin.so (0x6c62000)
If you are using dlopen for the loadable library, chances are that it was unloaded before the program terminates. Therefore Valgrind is unable to resolve its symbols. Try to avoid calling dlclose on this library. See http://valgrind.org/docs/manual/faq.html#faq.unhelpful for more information.

Embedding binary into elf with objcopy may cause alignment issues?

There have been a number of posts on stackoverflow and other places detailing how to embed binary blobs into elf binaries.
Embedding binary blobs using gcc mingw
and
C/C++ with GCC: Statically add resource files to executable/library
being the most complete answers.
But there's a possible issue which noone mentions. Here's a quicky foo.txt coverted to foo.o:
$ objdump -x foo.o
foo.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .data 0000000d 00000000 00000000 00000034 2**0
CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
00000000 l d .data 00000000 .data
0000000d g .data 00000000 _binary_foo_txt_end
0000000d g *ABS* 00000000 _binary_foo_txt_size
00000000 g .data 00000000 _binary_foo_txt_start
Now, I don't really grok all this output - is there documentation for this stuff??? I guess most of it is obvious enough "g" is global and "l" is local etc etc...
What stands out is the alignment for the .data segment set at 0. Does that mean what I think it means? ie: When it comes to linking, the linker will go "ah yeah, wherever..."
If you embed char data or are working on an x86 then you'll never notice. But if you embed int data or, as I'm doing, 16 and 32 bit data on an ARM, then you could get an alignment trap at any point.
My gut feeling is that this means that either objcopy needs another option to specify alignment of the binary blob, or it's broken and you shouldn't use this method at all.
To answer my own question, I'd assert that objcopy is broken in this instance. I believe that using assembly is likely the best way to go here using Gnu as. Unfortunately I'm now linux machine-less so can't test this properly but I'll put this answer here in case someone finds it or wants to check:
.section ".rodata"
.align 4 # which either means 4 or 2**4 depending on arch!
.global _binary_file_bin_start
.type _binary_file_bin_start, #object
_binary_file_bin_start:
.incbin file.bin
.align 4
.global _binary_file_bin_end
_binary_file_bin_end:
The underscores are the traditional way to annoy yourself with C/asm interoperability. In other words they vanish with MS/Borland compilers under Windows.
Create a linker script "lscript.ld"
MEMORY
{
memory : ORIGIN = 0x00000000, LENGTH = 0x80000000
}
SECTIONS
{
.data (ALIGN(4)) : {
*(.data)
*(.data.*)
__data_end = .;
} > memory
.text (ALIGN(4)) : {
*(.text)
*(.text.*)
__text_end = .;
} > memory
_end = .;
}
Link your file:
gcc -Wl,-T -Wl,lscript.ld -o linked_foo.elf foo.o
Find all the extraneous stuff added in linking:
objdump -x linked_foo.elf
Objcopy again, to remove the extra stuff:
objcopy --remove-section ".init_array" (repeat as necessary) --strip-all --keep-symbol "_binary_foo_txt_start" --keep-symbol "_binary_foo_txt_end" --keep-symbol "_binary_foo_txt_size" linked_foo.elf final_foo.elf
That gets you an elf file at 2**2 alignement.

Resources