xv6-public icon indicating copy to clipboard operation
xv6-public copied to clipboard

Fix for binutils >= 2.36

Open lorenzo-stoakes opened this issue 4 years ago • 8 comments

As-is trying to build with binutils 2.36 and a recent gcc is problematic in 2 ways:

  1. It fails to boot in qemu, getting stuck in a bootloop at 'Booting from Hard Disk..'
  2. fs.img fails to build due to an overzealous -Wstringop-overflow error in usertests.c combined with -Werror

This PR resolves both issues, firstly by stripping the newly introduced '.note.gnu.property' section introduced by binutils 2.36 which appears to be the source of the problem and secondly suppressing the -Wstringop-overflow warning in usertests.c.

The PR also strips some trailing space in the Makefile as trailing space is indeed, the devil.

lorenzo-stoakes avatar Jul 30 '21 21:07 lorenzo-stoakes

Thanks a lot! However I don’t know what happened. What should I do to understand the differences?

Miracle-1996 avatar Aug 17 '21 14:08 Miracle-1996

It looks like the ELF loader is assuming that this section is not present, from binutils 2.36 on it gets added by default which causes the system to fail to be able to correctly load userland binaries. The solution is to simply remove the section altogether. Of course an alternative might be to adjust the loader code.

I left this PR here not only in case a maintainer (though I realise the x86 version is no longer maintained) decided to merge but more so that somebody else who found xv6 broken could use this PR to fix things locally :)

lorenzo-stoakes avatar Aug 17 '21 14:08 lorenzo-stoakes

Yeah! I encounter the problem today when I compile this project in my Arch-Linux with binutils 2.36.1-3.

Miracle-1996 avatar Aug 17 '21 14:08 Miracle-1996

arch is the key motivator for this change as it is the distro I use. If you try this it should sort out the issue.

lorenzo-stoakes avatar Aug 17 '21 15:08 lorenzo-stoakes

Yes!Thanks a lot again! Actually the version which I compiled is the rev9. Today I compile it with "make qemu-nox" in the arch-linux rather than the ubuntu 18.04 which I used to use. I deleted the "Werror" in CFLAGS to deal with the "-Werror=stringop-overflow=". Then it compiles well. However it hang over in the "Booting From Hard Disk“. After I revising the Makefile according to your's file and the #115.,it works well!

Miracle-1996 avatar Aug 17 '21 15:08 Miracle-1996

I left this PR here not only in case a maintainer (though I realise the x86 version is no longer maintained) decided to merge but more so that somebody else who found xv6 broken could use this PR to fix things locally :)

Thanks for the PR. I fetched from your branch to make it work on Arch Linux. :)

officialcjunior avatar Oct 17 '21 10:10 officialcjunior

Thank You!!! hopefully they merge this PR soon!

McBride-SallyJoeBob avatar Oct 25 '21 06:10 McBride-SallyJoeBob

I think I understand why this is necessary. First, a small isolated testcase: $ cat initcode.c

void start() {
  return;
}

$ cat Makefile

CFLAGS = -m32 -march=i386
LDFLAGS = -m elf_i386

initcode: initcode.o
        $(LD) $(LDFLAGS) -N -e start -o $@ $<

initcode.o: initcode.c
        $(CC) $(CFLAGS) -c $<

In this case where we leave the addresses as their defaults, we can see that ld places .note.gnu.property before .text: $ readelf -S initcode

There are 9 section headers, starting at offset 0x2a4:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .note.gnu.pr[...] NOTE            080480b4 0000b4 000028 00   A  0   0  4
  [ 2] .text             PROGBITS        080480dc 0000dc 000021 00 WAX  0   0  1
  [ 3] .eh_frame         PROGBITS        08048100 000100 00004c 00   A  0   0  4
  [ 4] .got.plt          PROGBITS        0804814c 00014c 00000c 04  WA  0   0  4
  [ 5] .comment          PROGBITS        00000000 000158 00001b 01  MS  0   0  1
  [ 6] .symtab           SYMTAB          00000000 000174 000090 10      7   4  4
  [ 7] .strtab           STRTAB          00000000 000204 000050 00      0   0  1
  [ 8] .shstrtab         STRTAB          00000000 000254 000050 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), p (processor specific)

The sections start around 0x08048000, which is the arbitrary location used as the default start location for .text. [1]

When we do specify the address of the .text section, only it and sections after it will be placed at the beginning of the output file. Therefore, .note.gnu.property will remain wherever it was before. [2] $ ld -m elf_i386 -N -e start -Ttext 0 -o initcode initcode.o $ readelf -S initcode

There are 9 section headers, starting at offset 0x2b4:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .note.gnu.pr[...] NOTE            080480d4 000140 000028 00   A  0   0  4
  [ 2] .text             PROGBITS        00000000 0000d4 000014 00 WAX  0   0  1
  [ 3] .eh_frame         PROGBITS        00000014 0000e8 00004c 00   A  0   0  4
  [ 4] .got.plt          PROGBITS        00000060 000134 00000c 04  WA  0   0  4
  [ 5] .comment          PROGBITS        00000000 000168 00001b 01  MS  0   0  1
  [ 6] .symtab           SYMTAB          00000000 000184 000090 10      7   4  4
  [ 7] .strtab           STRTAB          00000000 000214 000050 00      0   0  1
  [ 8] .shstrtab         STRTAB          00000000 000264 000050 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), p (processor specific)

Then, because of that far-out section, when we convert the initcode to a binary, rather than getting a nice and small 44 (!) byte binary, we get a 16+ MiB binary which would take ages for the ELF loader to load from the image. To get an idea of how long it takes, I modified the bootloader to output progress over serial, and the answer is long.


Understanding this, let's explore our options for how to fix it. Deleting the .note.gnu.property section is a satisfactory solution, but I am interested in alternative solutions since the issue is not the existence of that section, but rather the location of it.

Unfortunately, the ld command line does not allow us to specify a "general" start address for our binary. It will only let us fix the start addresses of specific sections, such as .text or .note.gnu.property. Of course, fixing the address of the latter would not be a good solution because it would not be compatible with earlier versions of binutils, and does not clearly express our intent.

I think that the cleanest solution is to write a super small linker script that fixes .text to the beginning of the output file. While we are at it, we can also link directly into the binary format (this should also be applicable for earleir binutils).

Makefile

...
initcode: initcode.S
	$(CC) $(CFLAGS) -nostdinc -I. -c initcode.S
	$(LD) $(LDFLAGS) -T initcode.ld -o initcode -N initcode.o
	$(OBJDUMP) -S initcode.o > initcode.asm
...

initcode.ld

OUTPUT_FORMAT("binary")
ENTRY(start)

SECTIONS
{
    .text : {
        *(.text)
    }
}

CodingKoopa avatar Feb 25 '23 05:02 CodingKoopa