According to the ia64 ABI standard, the @secrel(expr) directive is supposed to compute a section-relative displacement as "the difference between expr and the address of the beginning of the (output) section that contains expr." However, at the moment, GNU ld (via BFD) calculates @secrel(expr) as the difference between expr and the address of the beginning of the (output) section that contains the @secrel() directive. The following example demostrates this: On ia64 linux: $ cat t.S .section "__my_text", "a" .section "__ex_table", "a" .section "__my_text" .global _start _start: { nop 0 } [1:] nop 1 { nop 2 } .section "__ex_table" data4 @secrel(1b) $ as t.S -o t.o $ ld t.o $ objdump --full --section __ex_table a.out a.out: file format elf64-ia64-little Contents of section __ex_table: 40000000000000e0 00000000 .... $ ld --version GNU ld version 2.15 Copyright 2002 Free Software Foundation, Inc. This program is free software; you may redistribute it under the terms of the GNU General Public License. This program has absolutely no warranty. If I do the same on HP-UX (using the GNU assembler but the HP-UX linker), I get: $ objdump --full --section __ex_table a.out a.out: file format elf32-ia64-hpux-big Contents of section __ex_table: 4000664 00000010 .... I believe the HP-UX linker is correct here: the difference between label 1b and the beginning of the section containing label 1b is indeed 0x10.
Fixed: http://sources.redhat.com/ml/binutils-cvs/2004-10/msg00199.html