[Prev][Next][Index][Thread]
Re: Overriding stuff from OSKit libs, some random remarks, and patches
Michael Hohmuth wrote:
> Unfortunately, this doesn't work as well as I thought
> at first. Even if all symbols in the OSKit libraries
> are weak, they are still preferred over non-weak
> symbols in my own library as described above.
> :-(
Looking in my Big Binder Of CS Articles,
I find this on page 1-18 of the TIS ELF specs:
"When the link editor combines several relocatable
object files, it does not allow multiple definitions
of STB_GLOBAL symbols with the same name. On the
other hand, if a defined global symbol exists, the
appearance of a weak symbol with the same name will
not cause an error. The link editor honors the
^^^^^^^^^^^^^^^^^^^^^^^^^^
global definition and ignores the weak ones."
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
So, the problem isn't there (I checked it,
GNU LD is okay).
What might be the problem, is this.
say you have a function A() in a file that calls another function B() in
the same file. The symbol
B is weak. Now there's a non-weak function B() in
a different file, which should replace the weak
one. However, because A() and B(weak) are in the
same file, could it be that GCC when it emits the
object file directly has A call the weak B, because
they're in the same file so it can directly emit
the correct code ? I always thought that this
wasn't the case, and that the linker is supposed
to relocate all symbols irregardless of where they
are defined. Turns out this is not the case...
Here are some test files:
----- foo.c
#include <stdio.h>
void foo(void) __attribute__((weak));
void foo(void)
{
printf("Foo! Bar!\n");
}
void bar(void)
{
foo();
}
----- foo2.c
#include <stdio.h>
void foo(void)
{
printf("Hah, you didn't think you'd get"
"that stupid text did you ?\n");
}
----- main.c
#include <stdio.h>
extern void bar(void);
extern void foo(void);
int main(void)
{
foo();
bar();
return 0;
}
-----
I get the following output:
[root@ramon temp]# ./test
Hah, you didn't think you'd get that stupid text did you ?
Foo! Bar!
[root@ramon temp]#
Blah, yuck, etc., this is not what we want.
Inspection of foo.o yields:
[root@ramon temp]# objdump --reloc ./foo.o
./foo.o: file format elf32-i386
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
00000004 R_386_32 .rodata
00000009 R_386_PC32 printf
[root@ramon temp]#
So GCC didn't actually emit a relocation entry
for the invocation of foo() in bar()... in which
case the linker cannot link it, of course. GCC
thinks the weak version of foo() is the right one
and produces code to reference it:
[root@ramon temp]# objdump --disassemble foo.o
foo.o: file format elf32-i386
Disassembly of section .text:
00000000 <foo>:
0: 55 pushl %ebp
1: 89 e5 movl %esp,%ebp
3: 68 00 00 00 00 pushl $0x0
8: e8 fc ff ff ff call 9 <foo+0x9>
d: 83 c4 04 addl $0x4,%esp
10: c9 leave
11: c3 ret
12: 89 f6 movl %esi,%esi
00000014 <bar>:
14: 55 pushl %ebp
15: 89 e5 movl %esp,%ebp
17: e8 e4 ff ff ff call 0 <foo>
1c: c9 leave
1d: c3 ret
[root@ramon temp]#
As I see it, the way to cleanly fix the problem
is to hack GCC adding another command line option,
which instructs it to emit relocation entries for
*all* symbols, even internally referenced ones.
This would slow down linking but then, if you need
it it's nice that you can use it. However, hacking
GCC doesn't sound like a trivial job (but then,
I have no experience with GCC's internals, it might
not be too hard).
Ramon
References: