At compile-time I link my Assembly bootstrap together with my kernel, into an *.img file, which I then convert into an *.iso image using MagicISO. I then boot from this *.iso image.
But the problem is that I want to read the second sector of the file (the kernel) into memory at 0x1000. But I only know how to do so, with a floppy disk image, so could someone please tell me how to do so, with an *.iso?
If you need any code or anything just tell me, and I'll provide it: ).
If your img file is a floppy image, the disc is loaded in a floppy-emulation environment. My conjecture is that you should be able to access the data just as you would on a floppy.
Related
I have built firmware for stm32f4, so I have *.elf an *.bin files. If I load *.bin file into internal flash it runs correctly. But if I want load this firmware to another address different from default (0x08000000) and run it from my bootloader, of course it does not works. I fix memory area address in project settings (I use CooCox 1.7.6 if it matter) and it begins runing from the bootloader.
I don't want rebuild project every time I load firmware in standalone mode or using bootloader. So I'm looking for method that will allow me to make *.bin files from *.elf, which will be able to load from the different addresses.
I tried manualy interupt vector table fixing. It allow me to run small blinker project but it doesn't work for more complex projects. I must be missing something.
Then I tried objcopy with --change-addresses but unfortunately it doesn't work. I get the same file without any difference.
I think, it is a general problem and there are solution for it but I must be missing something important.
You have to compile your code as position independent. See the -fpic and -fPIC options of gcc. Or you need a loader that understands the relocation table of the ELF image.
I just happened to complete an odyssey on STM32 Cortex-M4 (and M0) with Position-Independent Code firmware images operated by a bootloader. I will give you and overview and link the full article below. My evaluation board is NUCLEO-L432KC with target MCU STM32L432KCU6U. The magic goes like this:
On high level, there are couple of things needed:
A very simple bootloader. It only needs to read 2 4-byte words from the flash location of the firmware image. First is stack pointer address and second is Reset_Handler address. Bootloader needs to jump to Reset_Handler. But as the firmware is relocated further in the flash, the Reset_Handler is actually a bit further. See this picture for clarification:
So, bootloader adds the correct offset before jumping to Reset_Handler of the firmware image. No other patching is done, but bootloader (in my solution at least) stores location and offset of the firmware image, calculates checksum and passes this information in registers for the firmware image to use.
Then we need modifications in firmware linker file to force the ISR vector table in the beginning of RAM. For Cortex-M4 and VTOR (Vector Offset Table Register) the ISR vector table needs to be aligned to 512 boundary. In the beginning of RAM it is there naturally. In linker script we also dedicate a position in RAM for Global Offset Table (GOT) for easier manipulation. Address ranges should be exported via linker script symbols also.
We need also C compiler options. Basically these:
-fpic
-mpic-register=r9
-msingle-pic-base
-mno-pic-data-is-text-relative
They go to C compiler only! This creates the Global Offset Table (GOT) accounting.
Finally we need dedicated and tedious assembly bootstrap routines in the firmware image project. These routines perform the normal startup task of setting up the C runtime environment, but they additionally also go and read ISR and GOT from flash and copy them to RAM. In RAM, the addresses of those tables pointing to flash are offset by the amount the firmware image is running apart from bootloader. Example pictures:
I spent last 6 months researching this subject and I have written an in-depth article about it here:
https://techblog.paalijarvi.fi/2022/01/16/portable-position-independent-code-pic-bootloader-and-firmware-for-arm-cortex-m0-and-cortex-m4/
I do not think so that would work well in your case because when you are compiling the file to run with boot loader, you also needs to make sure that Interrupt vector also have been moved to the new location else there will be a problem in executing some of the functions.
knowing that similar questions have been asked a few times already, let me just explain what I'm trying to do and why: I have an embedded system which consists of an ARM Cortex-M4 microcontroller and an FPGA. The FPGA can be configured by an on-board flash memory without even needing the microcontroller. But sometimes it would be nice for the microcontroller to be able to reconfigure the FPGA, so it has access to the required programming signals.
The bitstream which needs to be sent to the FPGA is some 150kBytes, but changes much less frequently than the MCU firmware. Since programming that much data with the programmer/debugger (Segger J-Link) takes some time, I would prefer not to erase and reprogram this bitstream every time the firmware changes (but the bitstream is identical). The debugger does reprogram only those memory blocks which actually have changed, so it happily skipped programming of the bitstream if it would always be located at the same address. But this is obviously not the case if I just include it some way like
static const uint8_t fpga_bitstream[] = {
// ...
};
since the linker is free to decide where to place this data.
Now the question: What would be a (not too intrusive) way to have the linker put this symbol always to the same address? I am aware of the --defsym linker option, but this seems to be ignored when the symbol in question is defined in a source file (instead of just being referenced and declared as extern). The only way I know which works (I've used that some time ago already) is to use a custom linker file which defines a separate partition in the MEMORY part and then creates a new section to put the symbol into, using e.g.
static const uint8_t fpga_bitstream[] __attribute__((section(".fpgabitstream"))) = {
// ...
};
This project uses a small operating system (Nut/OS), however, which brings its own linker files. So I'd be fine if I could append some data to it using the -Tfile.ld option, but I'd prefer not having to change the original script, as this is located in the source tree of the operating system itself.
Thanks,
Philipp
As it doesn't seem to be possible to "add" to an existing linker script, probably the easiest solution would be to reserve a separate area of flash (e.g. an area at a fixed address near end with a little reserve for future growth) for the FPGA configuration and load from that fixed address.
Since there is probably nothing useful you can do to the FPGA bitstream anyway from the MCU side (other than loading it), I don't see any advantage in embedding the FPGA config into your MCU binary. You only need start address and size in your MCU code, both of which can be made known to the MCU by the --defsym linker option (without linker script modification).
I have a very similar configuration (with FPGA config and MCU code living on separate areas of flash) over here which works well. MCU flash is used regularily while FPGA is flashed only now and then.
I'm trying to write a basic userspace ELF loader that should be able to load statically linked (not dynamically linked) non-relocatable binaries (i.e. not built with -pie, -fPIE and so on). It should work on x86 CPU's for now.
I've followed the code on loading ELF file in C in user space and it works well when the executable is relocatable, but as expected completely fails if it isn't since the program is loaded in the wrong virtual memory range and instantly crashes.
But I tried modifying it to load the program at the virtual offset it expects (using phdr.p_vaddr) but I ran into a complication: my loader is already using that virtual memory range! I can't mmap it, much less write anything into it. How do I proceed so that I can load my non-relocatable binary into my loader's address space without overwriting the loader's own code before it's finished? Do I need to get my loader to run from a completely different virtual memory range, perhaps by getting the linker to link it way above the usual virtual memory range for a non-relocatable binary (which happens to start at 0x400000 in my case) or is there some trick to it?
I've read the ELF documentation (I am working with ELF64 here by the way, but I think ELF32 and ELF64 are very similar) and a lot of documents on the web and I still don't get it.
Can someone explain how an ELF loader deals with this particular complication? Thanks!
Archimedes called "heureka" when he found that at a location can only be one object. If your ELF binary must be at one location because you can't rebuild it for another location you have to relocate the loader itself.
The non-relocatable ELF doesn't include enough Information to move it to a different address. You could probably write a decompiler that detects all address references in the code but it's not worth. You will have problems when you try to analyze data references like pointers stored in pre-initialized variables.
Rewrite the loader if you can't get the source code of you ELF binary or a relocatable version.
BTW: Archimedes heureka was deadly for the goldsmith who cheated. I hope it's not so expensive in your case.
It's important to calculate correctly the value of TEXT_BASE when we begin to program the bootloader, but I haven't found a tutorial well explaining how to find this value according to platform datasheet or other materials. For example, for arm920t and sumsang s3c24x0, u-boot defines TEXT_BASE=0x33F80000 with this reason:
SMDK2410 has 1 bank of 64 MB DRAM
3000'0000 to 3400'0000
Linux-Kernel is expected to be at 3000'8000, entry 3000'8000 optionally with a ramdisk at 3080'0000
we load ourself to 33F8'0000
download area is 3300'0000
Can anyone explain the logic? Thanks!
ps: I also hope to know the memory layout of u-boot after load into the ram, the address of each data/instruction part, bss, rodata,zi, etc and the size. I expecte someone offer me some concerning tutorials to anaylyse, thank you!
TEXT_BASE is, unsurprisingly, the base address of the U-boot image i.e. where it starts executing from. So if U-boot is running straight from flash, it's the address of the flash. Or if ROM/firmware is responsible for loading U-boot then it's whatever address in RAM U-boot gets loaded to. Thus if you set TEXT_BASE to a different address it'll be linked wrong and will probably break at the relocation step.
As for the image layout, what's to ask? Either read the linker scripts, or just run a build then disassemble the u-boot ELF image that u-boot.bin is created from.
I am writing a simple user-space ELF loader under Linux (why? for 'fun'). My loader at the moment is quite simple and is designed to load only statically-linked ELF files containing position-independent code.
Normally, when a program is loaded by the kernel's ELF loader, it is loaded into its own address space. As such, the data segment and code segment can be loaded at the correct virtual address as specified in the ELF segments.
In my case, however, I am requesting addresses from the kernel via mmap, and may or may not get the addresses requested in the ELF segments. This is not a problem for the code segment since it is position independent. However, if the data segment is not loaded at the expected address, code will not be able to properly reference anything stored in the data segment.
Indeed, my loader appears to work fine with a simple assembly executable that does not contain any data. But as soon as I add a data segment and reference it, the executable fails to run correctly or SEGFAULTs.
How, if possible, can I fixup any references to the data segment to point to the correct place? Is there a relocation section stored in the (static) ELF file for this purpose?
If you modify the absolute addresses available in the .got section, (global offset table) your program should work. Make sure to modify the absolute address calculation to cater for the new distance between .text and .data, I'm afraid you need to figure out where this information comes from, for your architecture.
See this: Global Offset Table (Processor-Specific)
Good luck.
I don't see any way you can do that, unless you emulate the kernel-provided virtual address space completely, and run the code inside that virtual space. When you mmap the data section from the file, you are intrinsically relocating it to an unknown address of the virtual address space of your ELF interpreter, and your code will not be able to reference to it in any way.
Glad to be proven wrong. There's something very cool to learn here.