Using LD to output a flat binary?
Using LD to output a flat binary?
Hello, I've been working on a bootloader, and have recently run into trouble getting my linker (LD from binutils-2.16 targeting i386-elf, compiled in Cygwin) to output a flat binary correctly. I've tried various scripts I found while searching google, as well as a few I wrote myself after reading the documentation from the LD manpages; however, in the cases where the script works and produces a binary file, my dispstr() function (similar to puts() ) doesn't work. When I disassemble the binary file it appears that the string pointer passed to the function is an address somewhere above 0x8048000, which is LD's default virtual address (I think). So basically, I'm not sure what exactly is messing up; if anyone's had this problem before, or can offer any advice, it'd be greatly appreciated.
- Troy Martin
- Member
- Posts: 1686
- Joined: Fri Apr 18, 2008 4:40 pm
- Location: Langley, Vancouver, BC, Canada
- Contact:
Re: Using LD to output a flat binary?
Hmm, I'm not sure. You mind posting your most successful script for us so we can check it out?
Re: Using LD to output a flat binary?
Below is pretty much the 'defacto' standard for a minimal linker script for flat binaries. It will link everything to 0x10000. In your linkers did you ever include the *(.rodata) placement section? Also, could you give more specifics on what you are using to compile the code with (using just n/f/m/y/tasm/gcc/etc...) and could you post the compilation script/makefile.
Code: Select all
OUTPUT_FORMAT("binary")
ENTRY(start)
phys = 0x00010000;
SECTIONS
{
.text phys : AT(phys) {
code = .;
*(.text)
*(.rodata)
. = ALIGN(4096);
}
.data : AT(phys + (data - code))
{
data = .;
*(.data)
. = ALIGN(4096);
}
.bss : AT(phys + (bss - code))
{
bss = .;
*(.bss)
. = ALIGN(4096);
}
end = .;
}
Website: https://joscor.com
Re: Using LD to output a flat binary?
Well, the linker script posted worked just as well as the others, so that would be the most successful script; here's my makefile (I'm using MinGW's make tool, if you're wondering about the backwards slashes in the file paths)
You know, I'm actually not sure what every one of those GCC flags does; if any are redundant or possibly problematic, let me know and I'll rebuild everything without them and see if that fixes it.
EDIT: In case you're wondering, imgtool is a utility I wrote to make disk images, and all of this is a single-stage bootloader intended to be loaded from the first few sectors of the disk.
EDIT: I looked up what each of those flags does, and removed all the optimization-related ones, and it's still giving me weird addresses for strings (even when I declare them outside of the main function). I'm thinking it's something to do with .rodata having a weird virtual address, but the linker script posted has no indication of that being done. Still don't know exactly what's messing up.
Code: Select all
L = i386-elf-ld
LF = -T link -nostdlib -nostartfiles -nodefaultlibs
A = nasm
AF = -f bin
AE = -f elf
C = i386-elf-gcc
CF = --freestanding -fstrength-reduce -fomit-frame-pointer -finline-functions -fno-builtin -nostdlib -nostartfiles -nodefaultlibs -Wall -Werror -O0 -Iinc
all: bin\image.bin
bin\image.bin: bin\boot.bin
imgtool bin\image.bin bin\boot.bin image 1440k
bin\boot.bin: bin\aboot.bin bin\cboot.bin
copy /b bin\aboot.bin + bin\cboot.bin bin\boot.bin
bin\aboot.bin: boot.asm
$(A) $(AF) -o bin\aboot.bin boot.asm
bin\cboot.bin: bin\stub.o bin\boot.o
$(L) $(LF) -o bin\cboot.bin bin\stub.o bin\boot.o
bin\stub.o: stub.asm
$(A) $(AE) -o bin\stub.o stub.asm
bin\boot.o: boot.c
$(C) $(CF) -o bin\boot.o boot.c
EDIT: In case you're wondering, imgtool is a utility I wrote to make disk images, and all of this is a single-stage bootloader intended to be loaded from the first few sectors of the disk.
EDIT: I looked up what each of those flags does, and removed all the optimization-related ones, and it's still giving me weird addresses for strings (even when I declare them outside of the main function). I'm thinking it's something to do with .rodata having a weird virtual address, but the linker script posted has no indication of that being done. Still don't know exactly what's messing up.
Re: Using LD to output a flat binary?
Perhaps it isn't actually using the linker script? Try passing the following to LD:
Code: Select all
-Ttext [address] --oformat binary
All your base are belong to us.
Re: Using LD to output a flat binary?
Just tried that and had the same result; the code links fine, but string addresses are way off. Also I tried compiling a later version of binutils (2.18) and using it instead made no difference. Maybe it's due to binutils' target (i386-elf); a while ago when I was targeting i386-aout things were working fine (granted, the code was somewhat different, but it was still outputting a flat binary in the same manner).
Re: Using LD to output a flat binary?
Does including a .bss section really have any effect? AFAIK it needs file headers to be correctly initialised, which of course a flat binary lacks. So the effect is the same as if it hadn't been included at all.
Re: Using LD to output a flat binary?
I was under the impression that the linker would just zero out a section of the binary and use that for the uninitialized data; I could be wrong though.
Re: Using LD to output a flat binary?
No, the .bss section is normally initialised with zeroes only when loaded. The idea is that since it's not initialised anyway, there's no point in wasting space in the binary.
Re: Using LD to output a flat binary?
But if space outside of the binary is used for data, and there is no formatting in the binary to tell where this space is, wouldn't that cause undefined behavior due to the fact that there's no way to tell how much memory is being used beyond the end of the actual file?
Re: Using LD to output a flat binary?
That was my point in my first post.
Re: Using LD to output a flat binary?
What I was saying is that it's included in the binary as zeroes because of that. It wouldn't make sense to support flat binary output if such output would have unpredictable results from writing to unspecified memory locations.
EDIT: Could we get back on-topic? As far as I know, strings are in .rodata, not .bss.
EDIT: Could we get back on-topic? As far as I know, strings are in .rodata, not .bss.
Re: Using LD to output a flat binary?
Yes, I'm bumping, but i've also got some new information regarding my problem. After simplifying my build setup to just compile one .c file to one .o file, then link that .o file to a flat binary, I ran across this warning:
Now in the LD man page, it specifies that if start or _start aren't found, and no other start address is specified, the start address defaults to 0, so I'm not sure why it's doing this. What makes this interesting is that this start address is very close to my strange string addresses; it's almost as if whether I specify a start address or not, it silently sets it to 08048054 and links everything to that address. Does anyone know of what might be causing this problem, or how to fix it?
Code: Select all
/usr/cross/lib/gcc/i386-elf/4.2.0/../../../../i386-elf/bin/ld: warning: cannot find entry symbol _start; defaulting to 08048054