Page 1 of 1

ld inserts zeros without changing pointers

Posted: Tue Aug 16, 2011 3:16 pm
by Konorisius
I'm linking my files with ld but it adds zeros into it where none should be.
The command is
ld -e entry -T misc/sections -Map ./test.txt [files] -o [output]
If I look into the map file it looks fine:

Code: Select all

[...]
.data           0x001018c0      0xa00
 *(.data)
 .data          0x001018c0        0x0 crtbegin.o
 .data          0x001018c0      0x824 file_a.o
 .data          0x001020e4        0x0 file_b.o
[...]
 *fill*         0x001020e4       0x1c 00
 .data          0x00102100      0x140 file_e.o
 .data          0x00102240        0x0 file_f.o
[...]
 .data          0x00102240        0x0 crtend.o
[...]
The data section in file_a.o is really 0x824 bytes long and so on.
If I look at the start of the .data sector of file file_a.o it is:

Code: Select all

.data:00000848                           18 00 54 08 00 00 00 08
.data:00000850  6C 08 00 00 00 00 00 00  00 00 00 00 FF FF 00 00
.data:00000860  00 9A CF 00 FF FF 00 00  00 92 CF 00 00 00 08 00
.data:00000870  00 EF 00 00 00 00 08 00  00 EF 00 00 00 00 08 00
.data:00000880  00 EF 00 00 00 00 08 00 [...]
But in the result file the data sections starts with a lot of 00 bytes:

Code: Select all

.data:001018C0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
[...]
.data:00101970  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
.data:00101980  18 00 CC 18 10 00 00 08  E4 18 10 00 00 00 00 00
.data:00101990  00 00 00 00 FF FF 00 00  00 9A CF 00 FF FF 00 00 
.data:001019A0  00 92 CF 00 00 00 08 00  00 EF 00 00 00 00 08 00
.data:001019B0  00 EF 00 00 00 00 08 00  00 EF 00 00 00 00 08 00
There are more extra zeros after the .data section of file_a.o.
At the end of the .data section of the result file there should be the data of file_e.o and I think some garbage because of the length. 0x824+0x1C+0x140=0x980 and the whole data section should be 0xA00. But if I look at the end there is just the half of .data of file_e.o and then the 0xA00 bytes of the sections end with result that some data of file_e.o is missing.

There are some pointers in these memory dumps. If there were no zeros the pointers would be correct. The same is for the pointers in the code sections - without zeros everything would be fine.

In conclusion it seems to me that ld correctly collecting all data, calculated the new file and reset the pointers but by writing the file it adds the zeros truncating everything over the previously calculated size. As a result of this the created file is nothing more than trash.
I don't know the reason for this. Thus is why I am writing this post.

Why does ld do this and how can I tell it to create correct files?

Some more information:
I am working on Windows, using cygwin and using the integrated gcc (4.3.4 20090804, also tried 4.5.0) and ld (GNU Binutils 2.21.53.20110731). Thus it create a PE file. As a result of this I set up a multiboot header at nearly the start of the first section. QEMU is able to load the file and if I delete the extra zeros the OS also runs how it should be. But this is only possible because of the fact that I don't use file_e.o up to now. Without deleting the zeros QEMU just run into a triple fault while executing the fourth assembler line of the kernel because of the wrong GDT (just some garbage in memory).
An elf cross compiler is no option.

Re: ld inserts zeros without changing pointers

Posted: Sun Aug 21, 2011 9:48 am
by Bietje
May we see your link script?

You should use an ELF cross compiler.

Re: ld inserts zeros without changing pointers

Posted: Mon Aug 22, 2011 3:20 am
by Konorisius
Well it's not spectacular, just defining the order of the sections and the start point.
Here it is:

Code: Select all

*removed*
I tried something more. A previous version of BinUtils and thus ld, it links the same files with the same error. With GCC 4.5.0 there are more zeros in front of file_a.o. As a result of this, file_e.o is not in the .data section of the linked file any more.
The same goes with MinGW and GCC 4.5.2.
I tried to mix object files from GCC 4.3.4 and 4.5.2, not only file_a.o or file_e.o but all, and only use ld to link them to identify the object file causing this error. Some files add zeros other remove some. So all or nearly all of them influence the error.
I'm not sure but it seems that ld only inserts multiple of 32 Zero-Byte.



EDIT(forum time: Fri Sep 02, 2011 9:07 am):

Maybe some else have the same (specific) problem thus I what was wrong and how to fix it.

First of all, I used IDA to disassemble the file. IDA do not used the .data section as it is described in the header. It's nearly as it would be in RAM.
If I look into the file with a hex editor and interpret it myself I find a normal data section. Thus ld does not insert zeros at the start of the data section.

The linked file is loaded loaded as a block. The linker added zeros into the file to fit the file alignment (default 0x200). But it seems that it ignores the section alignment and put the section virtual one after another with alignment of 0x20 or lower. As a result of this, the .data section in RAM would be closer to the .text section than in the file. The linker calculated the pointers with this in mind.
Thus it seems to me that ld inserts zeros where none should be and IDA supports this, even the memory dump of qemu/gdb does.

I forced ld to use the same section alignment as the file alignment by adding "ALIGN(0x200)" to every section defined in the link script and using parameter "--file-alignment 0x200". Know it is correct in IDA and also QEMU do not reboot after triple fault.