Page 1 of 1

unresolvable R_X86_64_32S relocation

Posted: Wed Sep 05, 2007 9:30 pm
by bluecode
hi,

My OS currently has got a protected-mode and a longmode version. I use shared-libraries for libc (and other libraries). Since I use "-z nocopyreloc" for ld, I get "unresolvable R_X86_64_32S relocation" warnings (only about relocations to data in the shared-library) but only in my longmode version. But everything worked fine untill now. Today I had to discover painfully that under some circumstances this leads to real trouble. The following Code resulted from debugging binutil's cxxfilt (I know that this is worse code and non-standard conformant, but it did the job ;-) ):

Code: Select all

// NOTE: _sch_istable is an array of some type and it is in libiberty.so
printf("@ 0x%x\n", &_sch_istable[0]);
printf("@ 0x%x\n", &_sch_istable[c]);
And the output was:
@ 0x70045160
@ 0x90
That looks pretty weird :shock: (c is a character read from stdin)
Then I looked into the build log and found ld complaining about exactly that symbol with a "unresolvable R_X86_64_32S relocation"... So my question is basically how could I fix that :?:
I implemented shared-libraries like this: The code of a shared-library is shared between all process's and the data is copy-on-write. When I load a library I save all the symbols in a global list. If another shared-library or a process needs one of the symbols it looks into that table and the relocation is done with the information from this global table.
The normal ld behaviour would be to copy all data from the shared-libraries into the userspace app. But some libraries (e.g. libc++) need symbols from other libraries (e.g. a FILE structure for stdout). And since I don't want to patch libc++'s code for every process differently, I use -z nocopyreloc. That basically tells ld not to copy the shared-libraries data into the userspace (this would normally be done via a special relocation type), but to use the address from the shared-library. This works fine for x86, but it results in ld warnings on x86-64.

My current compile/link flags for applications (for x86-64) look like this:
C_FLAGS= -std=gnu99 -nostdlib -fno-builtin -Wall -fno-omit-frame-pointer -m64
LD_FLAGS= -z nocopyreloc
Adding -mcmodel=medium did not change anything. iirc I also tried to compile the libraries with fPIC (instead of fpic) and this also did not change a thing.

In case anyone wants to get his/her hands dirty you could do a subversion checkout and try to build lightOS yourself (But that implies building a cross-compiler...).

I hope I posted all the information needed. If there is anything missing, just ask for it :idea:

Posted: Wed Sep 05, 2007 9:54 pm
by bluecode
I think ld just leaves out the R_X86_64_32S relocation :shock:

My cxxfilt.o looks like:

Code: Select all

 306:	45 89 ec             	mov    %r13d,%r12d
 309:	0f b6 c3             	movzbl %bl,%eax
 30c:	f6 84 00 00 00 00 00 	testb  $0x8c,0x0(%rax,%rax,1)
			30f: R_X86_64_32S	_sch_istable
and objdump shows:
objdump cxxfilt.o -r | grep _sch_istable
000000000000030f R_X86_64_32S _sch_istable
The final executeable looks like:

Code: Select all

  400466:	45 89 ec             	mov    %r13d,%r12d
  400469:	0f b6 c3             	movzbl %bl,%eax
  40046c:	f6 84 00 00 00 00 00 	testb  $0x8c,0x0(%rax,%rax,1)
and the relocation is gone in objdump.

Posted: Wed Sep 12, 2007 5:41 pm
by bluecode
Ok, I "fixed" the problem: I compile my whole userspace now with -fpic (for x86-64). To get this working I had to do some smaller changes in my elf loader.
Imho this is a hack... Perhaps the large code model fixes that.

Posted: Thu Sep 13, 2007 6:39 pm
by speal
I'm also using the -fPIC option to "fix" this problem. I was told at the time there was basically no penalty for using PIC in long mode, since offsets can be larger. I'll try to find the explanation, but I remember being convinced enough not to look for another solution.

If you plan to keep the entire upper half of address space for the kernel, you'll need to stick with the -fPIC option, since there are no implemented memory models for the 64 bit target that will allow for that range of addresses (thanks GCC). When asked why it wasn't implemented, a GCC developer said "that would be a bad way to do it, so we aren't implementing it." I guess they're saving us from ourselves, but I would have liked the option. This is all as of GCC 4.1.2, however.

Posted: Fri Sep 14, 2007 1:01 am
by bluecode
speal wrote:I'm also using the -fPIC option to "fix" this problem.
For me -pic (note the small letters) was sufficient. At least I had no errors/warnings through compiler phase.
I was told at the time there was basically no penalty for using PIC in long mode, since offsets can be larger.
I have the feeling that the code gets slightly bigger. But it is not that worse.
If you plan to keep the entire upper half of address space for the kernel, you'll need to stick with the -fPIC option, since there are no implemented memory models for the 64 bit target that will allow for that range of addresses (thanks GCC).
Well, I stick with mcmodel=kernel.
btw. the gcc roadmap says, that the large code model will be in gcc 4.3.