IAIK/sweb

Doesn't build in gcc 8.1

Closed this issue · 4 comments

Sweb doesn't build in the new gcc, there are some minor errors about fallthroughs in switches and some const casts in ustl to remove, but the main issue which I didn't find any fix for, is the issue with the truncated addresses in boot.32.C which was already opened as an issue earlier this year. Here the beginning of the ld error message I get:

/tmp/sweb/lib/libarch_x86_64.a(boot.32.C.o): In function `setSegmentDescriptor(unsigned int, unsigned int, unsigned int, unsigned int, unsigned char, unsigned char, unsigned char)':
boot.32.C:(.text+0x76): relocation truncated to fit: R_X86_64_32 against symbol `gdt' defined in .bss section in /tmp/sweb/lib/libarch_x86_64.a(boot.32.C.o)
/tmp/sweb/lib/libarch_x86_64.a(boot.32.C.o): In function `entry':
boot.32.C:(.text+0x1bb): relocation truncated to fit: R_X86_64_32 against `.rodata'

there are about ten of these errors shown and the rest of them omitted.
I think it all boils down to the truncate macro and the new gcc not using relative jumps in this case, though I don't know how to fix it.

the ustl problems should be fixed by pulling in an updated version

I found a way to get the TRUNCATE macro to work with GCC 8.1.

Note: only tested with minimal reproducible examples, not a whole SWEB build
TL;DR: Split the TRUNCATE macro in two, godbolt link

Pros:

  • works on GCC 8
  • can be made to work with optimizations

Cons:

  • cannot be used in an arbitrary expression

Example:

Broken C

#define TRUNCATE(X) (char*)(((unsigned int)(((char*)X)+0x7FFFFFFF))+1)

char * foo = TRUNCATE(&global_foo);

GCC 7 -O0

mov     eax, OFFSET FLAT:global_foo+2147483647
add     eax, 1
mov     DWORD PTR [ebp-12], eax

GCC 8 -O0

mov eax, OFFSET FLAT:global_foo
add eax, -2147483648
mov DWORD PTR [ebp-12], eax

The problem is that GCC 8 sees a simple constant propagation and combines the two adds, leading to a constant too high to fit into the addend of a relocation.

The only way I found that makes this work is saving to an intermediate location.

Working C

#define TRUNCATE_A(X) (unsigned int)(((char*)X)+0x7FFFFFFF)
#define TRUNCATE_B(X) (char*)(X+1)

unsigned int temp_foo = TRUNCATE_A(&global_foo);
char * foo = TRUNCATE_B(temp_foo);

GCC 7 -O0

mov eax, OFFSET FLAT:global_foo+2147483647
mov DWORD PTR [ebp-12], eax
mov eax, DWORD PTR [ebp-12]
add eax, 1

GCC 8 -O0

mov eax, OFFSET FLAT:global_foo+2147483647
mov DWORD PTR [ebp-12], eax
mov eax, DWORD PTR [ebp-12]
add eax, 1

This works now.

Both approaches don't work with optimizations (both do the constant propagation and eliminate the variable). Making the variable volatile fixes this.

Should be fixed in the gccv8_updates branch on master.