Bootloader is seperated into 2 stages. First stage is written in assembly and only loads second stage, second stage is in C. Stage1 loads code in C to address 0x0500:0, and jumps there. Stage2 have to write "hello message" and halt.
I tried different ways to set starting address to raw binary made by: (but nothing worked)
cc -nostartfiles -nostdlib -c stage2.c
ld -s -T scrptfile.ld stage2.o /* I'm using ld just to set starting address of executable */
objcopy -O binary stage2 stage2.bin /* delete all unuseful data */
Linker script
SECTIONS
{
. = 0x0500;
.text : { *(.text)}
.data : { *(.data)}
.bss : { *(.bss)}
}
Maybe I delete with objcopy somethnig that shouldt be deleted.
How can I execute this stage2.bin then?
As I understand, written C code using 32-bits length instructions, when raw binary allows only 16?
P.S. Parameter -set-start (objcopy) returns an error: Invalid bfd target. It is because output file is binary?
Thank you for answers.
. = 0x0500 does not correspond to 0x0500:0. 0x0500:0 is physical address 0x5000, not 0x500.
Also, if you're trying to compile C code as 32-bit and run it in real mode (which is 16-bit), it won't work. You need to either compile code as 16-bit or switch the CPU into 32-bit protected mode. There aren't that many C compilers still compiling 16-bit code. Turbo C++ is one, Open Watcom is another. AFAIK, gcc can't do that.
Finally, I'm guessing you expect the entry point to be at 0x500:0 (0x5000 physical). You need to either tell this to the linker (I don't remember how, if at all possible) or deal with an arbitrary location of the entry point (i.e. extract it from the binary somehow).
Related
I'm attempting to convert an assembly file to C++ for use as a small and easy to insert "trampoline" loader for another library. It is injected into another program at runtime, then loads a library, runs a function inside of it, and frees it. This is simply to avoid needing multiple lengthy calls to WriteProccessMemory, and to allow certain runtime checks if needed.
Originally, I wrote the code in assembly as it gave me a high degree of control over the structure of the file. I ended up with a ~128 byte file structured as followed:
<Relocation Header> // Table of function pointers filled in by the loading code
<Code>
<Static Data>
The size/structure of the header is known at compile-time, also allowing the entry point to be calculated, so there is very little code needed to load this.
The problem is that sharing the structure of the header between my assembler (NASM) and compiler (GCC) is... difficult, hence the rewrite.
I've come up with this series of commands to compile/link the C++ code:
g++ -c -O3 -fpic Loader.cpp
g++ -O3 -shared -nostdlib Loader.o
Running objcopy -O binary -j .text a.exe then gives a binary file only about 95 bytes in size (I manually inserted some padding in the assembly version to make it clear when debugging where "sections" are).
Only one problem (at least for this question), the variable offsets haven't been relocated (obviously). Viewing the binary, I can see lines like mov rcx, QWORD PTR [rip+0x4fc9]. Clearly, this will not be valid in a 95 byte file. Is there a way (preferably using GCC or a program in Binutils) that I can get a stripped binary with correct offsets? The solution doesn't have to be a post-process like objcopy, it can happen during any part of the build proccess.
I'd really like to avoid any unneeded information in the file, it wouldn't necessarily be detrimental, but this is meant to be super lightweight. The file does not need to be directly runnable (the entry-point does not have to be 0).
Also to be clear, I'm not asking for a simple addition/subtraction to all pointers, GCC's generated addresses are spread across memory, they should be up against the code.
Although incomplete and needing some changes, I think I've come up with a functioning solution for now.
I compile as before, but link with a slightly different command: g++ -T lnkscrpt.txt -O3 -nostdlib Loader.o (-shared just makes the linker complain about missing a DllMain).
lnkscrpt.txt is an ld linker script (https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_5.html#SEC5) as follows:
SECTIONS
{
. = 0x00;
.bss : { *(.bss) }
.text : { *(.text) }
.data : { *(.rdata) *(.data) }
/DISCARD/ : {*(*)}
}
This preserves the order I want and discards any other default sections.
Finally I run objcopy -O binary -j .* --set-section-flags .bss=alloc,load,contents a.exe
to copy over the remaining sections to a flat binary. The --set-section-flags option simply insures that the binary contains space allocated for the .bss section.
This results in a 128 byte binary, laid out in the exact same way as my custom assembly version, using correct offsets, and not containing any unneeded data.
I have a linker script in which I have defined a section for containing the checksum of a software image. Something like:
...
.my_checksum :
{
__checksum_is_here = .;
KEEP (*(.my_checksum))
. = ALIGN(4);
_sw_image_code_end = .;
} > IMAGE
...
The checksum is placed into that section by using objcopy --update-section.
I build an elf file by using the arm gcc compiler, and I can see this section and its value within it:
> arm-none-eabu-objdumph -h my_elf_file.elf
...
0 .text 0001496c 08010000 08010000 00010000 2**4
...
7 .my_checksum 00000004 080250c0 080250c0 000350c0 2**2
...
// Notice that 000350c0 is the file offset and 080250c0 is the LMA.
// The starting LMA is 08010000
And I can retrieve its value:
> xxd -s 0x000350c0 -l 4 my_elf_file.elf
000350c0: 015e 028e // I have checked this value and it is correct.
Now I generate a bin file by executing
> arm-none-eabi-objcopy -O binary --gap-fill 0xFF -S my_elf_file.elf my_elf_file.bin
Now, if I try to read the checksum value again, using the difference between the checksum LMA and the first section LMA (see above):
> xxd -s 0x150c0 -l 4 my_elf_file.bin
The result I obtain here is different from the one obtained in the elf file, that is, the checksum section has been removed by objcopy. (That's what I think at least).
Nevertheless, If I define this in my main.c file:
static volatile unsigned int __aux_checksum __attribute__((section(".my_checksum")));
...
int main() {
...
((void)__aux_checksum); // Avoid compiler/linker optimizations.
...
}
Now, if I replicate the same steps as above with the elf and bin files (using the proper offsets), I can retrieve the checksum from the bin file (elf and bin give the same result).
Questions
My first question is: I know that you can define a section using __attribute__((section)), but if you use a section already defined within the linker script, does this command changes its behaviour for placing the variable within the section, instead of creating a new one?
My second question is: Is this the only way for preventing objcopy of removing this particular section?
Lets answer your 2nd question first,
Is this the only way for preventing objcopy of removing this particular section?
You need a concept as documented in the gnu LD manual under SECTIONS.
4.6.8.1. Output Section Type
Each output section may have a type. The type is a keyword in parentheses. The following types are defined:
NOLOAD
The section should be marked as not loadable, so that it will not be loaded into memory when the program is run.
DSECT, COPY, INFO, OVERLAY
These type names are supported for backward compatibility, and are rarely used. They all have the same effect: the section should be marked as not allocatable, so that no memory is allocated for the section when the program is run.
The linker normally sets the attributes of an output section based on the input sections which map into it. You can override this by using the section type. For example, in the script sample below, the ROM section is addressed at memory location 0 and does not need to be loaded when the program is run. The contents of the ROM section will appear in the linker output file as usual.
SECTIONS {
ROM 0 (NOLOAD) : { … }
…
}
So what does that mean? Say you have debugging info in your objects. If you are burning a ROM image you probably don't want to place the debugging info in the object. As well, the BSS segment is all zero and there is no need to store it to ROM, but you need to clear our RAM (at the load address) to make way for it. The 'init value' for the .data section is initialized from ROM but resides in RAM. The concepts are 'loadable' and 'allocatable' and they have flags for them in an ELF file. By default your .my_checksum gets no flags. Ie, not allocated and not loadable like debug info.
I know that you can define a section using attribute((section)), but if you use a section already defined within the linker script, does this command changes its behaviour for placing the variable within the section, instead of creating a new one?
From the above,
The linker normally sets the attributes of an output section based on the input sections which map into it.
Your input sections flags get inherited by your output section. So you have put in at least allocatable as a flag.
I would suggest that you just put your checksum at the end of either .text or .data. For instance, input secttions .rodata (constant values) usually get put with the output .text. There is usually no need to invent another output sections unless you want some book keeping that wont get to the final image. Your __checksum_is_here label is sufficient to find it and you can look at this question on CRCs.
I am writing a simple hello world bootloader in C with inline assembly using this article. Nothing fancy, no kernel loading and other advanced topics. Just a plain old "hello world" message.
Here are my files:
boot.c
/* generate 16-bit code */
__asm__(".code16\n");
/* jump boot code entry */
__asm__("jmpl $0x0000, $main\n");
/* user defined function to print series of characters terminated by null
character */
void printString(const char* pStr) {
while (*pStr) {
__asm__ __volatile__ (
"int $0x10" : : "a"(0x0e00 | *pStr), "b"(0x0007)
);
++pStr;
}
}
void main() {
/* calling the printString function passing string as an argument */
printString("Hello, world!");
}
boot.ld
ENTRY(main);
SECTIONS
{
. = 0x7C00;
.text : AT(0x7C00)
{
*(.text);
}
.sig : AT(0x7DFE)
{
SHORT(0xaa55);
}
}
I then ran the following commands: (different from the first article; adapted from another StackOverflow article as the commands in the first article won't work for me)
gcc -std=c99 -c -g -Os -march=i686 -m32 -ffreestanding -Wall -Werror boot.c -o boot.o
ld -static -T boot.ld -m elf_i386 -nostdlib --nmagic -o boot.elf boot.o
The first line compiles successfully, but I get errors upon executing the second line:
ld: warning: cannot find entry symbol main; defaulting to 0000000000007c00
boot.o:boot.c:(.text+0x2): undefined reference to 'main'
boot.o: In function 'main':
C:(...)/boot.c:16: undefined reference to '__main'
C:(...)/boot.c:16:(.text.startup+0xe): relocation truncated to fit: DISP16 against undefined symbol '__main'
What's wrong? I use Windows 10 x64 with the gcc compiler that comes with Dev-C++.
I'd suggest an i686-elf cross compiler rather than using a native windows compiler and tool chain. I think part of your problem is peculiarities related to the Windows i386pe format.
The .sig section is likely not being written at all since that unknown section probably isn't marked allocatable data. The result of that is the signature isn't written to the final binary file. It is also possible the virtual memory address (VMA) is not being set in boot.ld so it may not advance the boot signature into the last 2 bytes of the 512 byte sector. As well with the Windows format read only data will be placed in sections starting with .rdata. You'll want to make sure those are included after the data section and before the boot signature. Failure to do this will default the linker script into placing unprocessed input sections at the end beyond the boot signature.
Assuming you have made the changes as you mentioned in the comments about the extra underscores your files may work this way:
boot.ld:
ENTRY(__main);
SECTIONS
{
. = 0x7C00;
.text : AT(0x7C00)
{
*(.text);
}
.data :
{
*(.data);
*(.rdata*);
}
.sig 0x7DFE : AT(0x7DFE) SUBALIGN(0)
{
SHORT(0xaa55);
}
}
The commands to compile/link and adjust the .sig section to be a regular readonly allocated data section would look like:
gcc.exe -std=c99 -c -g -Os -march=i686 -m32 -ffreestanding -Wall -Werror boot.c -o boot.o
ld.exe -mi386pe -static -T boot.ld -nostdlib --nmagic -o boot.elf boot.o
# This adjusts the .sig section attributes and updates boot.elf
objcopy --set-section-flags .sig=alloc,contents,load,data,readonly boot.elf boot.elf
# Convert to binary
objcopy -O binary boot.elf boot.bin
Other Observations
Your use of __asm__(".code16\n"); will not generate usable code for a bootloader. You'll want to use the experimental pseudo 16-bit code generation that forces the assembler to modify instructions to be compatible with 32-bit code but encoded to be usable in 16-bit real mode. You can do this by using __asm__(".code16gcc\n"); at the top of each C/C++ files.
This tutorial has some bad advice. The global level basic assembly statement that does the JMP to main may be relocated to somewhere other than the beginning of the bootloader (some optimization levels may cause this). The startup code doesn't set ES, DS, CS to 0x0000, nor does it set the SS:SP stack segment and pointer. This can cause problems.
If trying to run from a USB drive on real hardware you may find you'll need a Boot Parameter Block. This Stackoverflow Answer I wrote discusses this issue and a possible work around under Real Hardware / USB / Laptop Issues
Note: The only useful code that GCC currently generates is 32-bit code that can run in 16-bit real mode. This means that you can't expect this code to run on a processor earlier than a 386 like the 80186/80286/8086 etc.
My general recommendation is to not create bootloaders with GCC unless you know what you are really doing and understand all the nuances involved. Writing it in assembly is probably a much better idea.
If you want a C/C++ compiler that generates true 16-bit code you may wish to look at OpenWatcom
I have an application which runs on bare metal target and has the following structure
main.c
service.c/.h
It's compiled to ELF executable (system.elf) using standard gcc -c, ld sequence. I use linker to generate a map file showing adresses of all symbols.
Now, without re-flashing my system I need to add an extra functionality with a custom run-time loader. Remember, this is a bare-metal with no OS.
I'd like to
compile extra.c which uses APIs defined in service.h (and somehow link against existing service.o/system.elf)
copy the resulting executable to my SDRAM at runtime and jump to it
loaded code should be able to run and accesses the exported symbols from service.c as expected
I thought I'd be able to to reuse map file to link the extra.o against system.elf but this didn't work:
ld -o extraExe extra.o system.map
Does gcc or ld have some mode to make this late linking procedure? If not, how can I achieve dynamic code loading which I outlined above?
You can use the '-R filename' or '--just-symbols=filename' command options in ld. It reads symbol names and their addresses from filename, but does not relocate it or include it in the output. This allows your output file to refer symbolically to absolute locations of memory defined in your system.elf program.
(refer to ftp://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_3.html).
So here filename will be 'system.elf'. You can compile extra.c with GCC normally including services.h but without linking and generate 'extra.o' then call ld as below:
ld -R"system.elf" -o"extra.out" extra.o
The 'extra.out' shall have your symbols linked. You can use objdump to compare contents of both 'extra.out' and 'extra.o'.
Note that you can always pass the start address of your program to the ld (e.g. -defsym _TEXT_START_ADDR=0xAAAA0123) as well as start address of other memory sections like bss,data. (i.e. -Tbss, -Tdata)
Be careful to use a valid address that does not conflict with your 'system.elf' as ld will not generate error for that. You can define new areas for the loaded code+data+bss in your original linker script and re-compile the system.elf then point the start addresses to your defined areas while linking 'extra.o'.
I know there are some other similar questions about this out there, be it StackOverflow or not. I've researched a lot for this, and still didn't find a single solution.
I'm doing an operative system as a side project. I've been doing all in Assembly, but now I wanna join C code.
To test, I made this assembly code file (called test.asm):
[BITS 32]
GLOBAL _a
SECTION .text
_a:
jmp $
Then I made this C file (called main.c):
extern void a(void);
int main(void)
{
a();
}
To link, I used this file (called make.bat):
"C:\minGW\bin\gcc.exe" -ffreestanding -c -o c.o main.c
nasm -f coff -o asm.o test.asm
"C:\minGW\bin\ld.exe" -Ttext 0x100000 --oformat binary -o out.bin c.o asm.o
pause
I've been researching for ages, and I'm still struggling to find an answer. I hope this won't be flagged as duplicate. I acknowledge about the existence of similar questions, but all have different answers, and none work for me.
Question: What am I doing wrong?
Old MinGW versions had the problem that "ld" was not able to create non-PE files at all.
Maybe current versions have the same problem.
The work-around was creating a PE file with "ld" and then to transform the PE file to binary, HEX or S19 using "objcopy".
--- EDIT ---
Thinking about the question again I see two problems:
As I already said some versions of "ld" have problems creating "binary" output (instead of "PE", "ELF" or whatever format is used).
Instead of:
ld.exe --oformat binary -o file.bin c.o asm.o
You should use the following sequence to create the binary file:
ld.exe -o file.tmp c.o asm.o
objcopy -O binary file.tmp file.bin
This will create an ".exe" file named "binary.tmp"; then "objcopy" will create the raw data from the ".exe" file.
The second problem is the linking itself:
"ld" assumes a ".exe"-like file format - even if the output file is a binary file. This means that ...
... you cannot even be sure if the object code of "main.o" is really placed at the first address of the resulting object code. "ld" would also be allowed to put the code of "a()" before "main()" or even put "internal" code before "a()" and "main()".
... addressing works a bit differently which means that a lot of padding bytes will be created (maybe at the start of the file!) if you do something wrong.
The only possibility I see is to create a "linker script" (sometimes called "linker command file") and to create a special section in the assembler code (because I normally use another assembler than "nasm" I do not know if the syntax here is correct):
[BITS 32]
GLOBAL _a
SECTION .entry
jmp _main
SECTION .text
_a:
jmp $
In the linker script you can specify which sections appear in which order. Specify that ".entry" is the first section of the file so you can be sure it is the first instruction of the file.
In the linker script you may also say that multiple sections (e.g. ".entry", ".text" and ".data") should be combined into a single section. This is useful because sections are normally 0x1000-byte-aligned in PE files! If you do not combine multiple sections into one you'll get a lot of stub bytes between the sections!
Unfortunately I'm not the expert for linker scripts so I cannot help you too much with that.
Using "-Ttext" is also problematic:
In PE files the actual address of a section is calculated as "image base" + "relative address". The "-Ttext" argument will influence the "relative address" only. Because the "relative address" of the first section is typically fixed to 0x1000 in Windows a "-Ttext 0x2000" would do nothing but filling 0x1000 stub bytes at the start of the first section. However you do not influence the start address of ".text" at all - you only fill stub bytes at the start of the ".text" section so that the first useful byte is located at 0x2000. (Maybe some "ld" versions behave differently.)
If you wish that the first section of your file is located at address 0x100000 you should use the equivalent of "-Ttext 0x1000" in the linker script (-Ttext is not used if a linker script is used) and define the "image base" to 0xFF000:
ld.exe -T linkerScript.ld --image-base 0xFF000 -o binary.tmp a.o main.o
The memory address of the ".text" section will be 0xFF000 + 0x1000 = 0x100000.
(And the first byte of the binary file generated by "objcopy" will be the first byte of the first section - representing memory address 0x100000.)