Package: binutils Version: 2.16.1-2 Severity: normal I've attached a C source file where ld from binutils >= 2.16.1-1 screws up, relocating a call in the wrong way. I had no problems with 2.15.*.
I hope a little excerpt from the source code and disasm dumps from compiled programs will help. It is a cutted down version of a syscall benchmarking tool I coded up, and it tries to do a syscall via the vsyscall DSO which is provided by 2.6 kernels on i386. ==== benchmark.c ==== static force_inline void DO_sysenter() { asm volatile( // syscall 17 on Linux/i386 is ni_syscall -> // not implemented // Probably check this before trying this out "movl $17,%%eax\n\t" "call 0xffffe400\n\t" ::: "eax", "ecx", "edx"); } ===================== With binutils 2.15-6 installed, gcc generated that code, which is what I want (that's the entry point of the virtual syscall code the kernel provides). ==== objdump -d benchmark.2.15-6 ==== 80483a5: b8 11 00 00 00 mov $0x11,%eax 80483aa: e8 51 60 fb f7 call ffffe400 <_end+0xf7fb4e14> ===================================== With binutils 2.16.1-1 I get: ==== objdump -d benchmark.2.16.1-1 ==== 80483b6: b8 11 00 00 00 mov $0x11,%eax 80483bb: e8 fc e3 ff ff call 80467bc <_init-0x1ac4> ===================================== It seems clear that the new binutils relocated the symbol marked as *ABS* in a wrong way (relative to the current location instead of absolute): (0x80483bb + 0xffffe400) % 2**32 == 0x80467bb This results in a segfault for me. Some more information I managed to dig up: gcc -O2 -Wall -ggdb -S -o benchmark.S benchmark.c as benchmark.S -o benchmark.o objdump -d -r benchmark.o ===================================== benchmark.o: file format elf32-i386 Disassembly of section .text: 00000000 <main>: 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: 83 ec 08 sub $0x8,%esp 6: 83 e4 f0 and $0xfffffff0,%esp 9: 83 ec 1c sub $0x1c,%esp c: 68 00 00 00 00 push $0x0 d: R_386_32 .rodata.str1.1 11: e8 fc ff ff ff call 12 <main+0x12> 12: R_386_PC32 puts 16: b8 11 00 00 00 mov $0x11,%eax 1b: e8 fc e3 ff ff call ffffe41c <main+0xffffe41c> 1c: R_386_PC32 *ABS* 20: 31 c0 xor %eax,%eax 22: c9 leave 23: c3 ret ===================================== So far this is the same, no matter what version of gcc/binutils I use. Trying to link that together with ld, with a commandline stolen from an strace of gcc (slightly modified library {,search }paths): ld --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 \ -o benchmark /usr/lib/crt1.o /usr/lib/crti.o \ /usr/lib/gcc/i486-linux-gnu/4.0.2/crtbegin.o \ -L/usr/lib/gcc-lib/i486-linux-gnu/3.3.6/ \ -L/usr/lib/gcc-lib/i486-linux-gnu/3.3.6/../../.. benchmark.o -lgcc \ --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s \ --no-as-needed /usr/lib/gcc-lib/i486-linux-gnu/3.3.6/crtend.o \ /usr/lib/crtn.o Looking at the produced executable now shows this: objdump -d benchmark.2.15-7 | grep '$0x11,' -A 5 ===================================== 80483b6: b8 11 00 00 00 mov $0x11,%eax 80483bb: e8 40 60 fb f7 call ffffe400 <_end+0xf7fb4df0> 80483c0: 31 c0 xor %eax,%eax 80483c2: c9 leave 80483c3: c3 ret 80483c4: 90 nop ===================================== Looks quite reasonable (notice version 2.15-7) objdump -d benchmark.2.16.1-1 | grep '$0x11,' -A 5 ===================================== 80483b6: b8 11 00 00 00 mov $0x11,%eax 80483bb: e8 fc e3 ff ff call 80467bc <_init-0x1ac4> 80483c0: 31 c0 xor %eax,%eax 80483c2: c9 leave 80483c3: c3 ret 80483c4: 90 nop ===================================== Well, this sucks, ld relocated a symbol marked *ABS* as relative to the current location. The call goes somewhere to nirvana, which causes a segfault. I'm not sure whether this was intended or not, but I don't really think so, and it's not documented anywhere too. I've had a quick look at the source, but I didn't see anything obvious. Maybe I can have a deeper look tomorrow. If you have more questions (probably hard after my lengthy bugreport), just mail me. Cheers, Christian Aichinger -- System Information: Debian Release: testing/unstable APT prefers unstable APT policy: (500, 'unstable'), (500, 'testing'), (1, 'experimental') Architecture: i386 (i686) Shell: /bin/sh linked to /bin/bash Kernel: Linux 2.6.13-rc1r20050702 Locale: [EMAIL PROTECTED], [EMAIL PROTECTED] (charmap=UTF-8) Versions of packages binutils depends on: ii libc6 2.3.5-3 GNU C Library: Shared libraries an binutils recommends no packages. -- no debconf information
#include <stdio.h> #define force_inline __attribute__((always_inline)) inline static force_inline void DO_sysenter() { asm volatile( // syscall 17 on Linux/i386 is ni_syscall -> // not implemented // Used this to benchmark syscall overhead "movl $17,%%eax\n\t" "call 0xffffe400\n\t" ::: "eax", "ecx", "edx"); } int main(int argc, char *argv[]) { printf("I: Starting up\n"); DO_sysenter(); return 0; }
signature.asc
Description: Digital signature