シンボル間の引き算

再配置情報について調べてたらアセンブリでのシンボル間の引き算についてelf/i386mach-o/x86-64で挙動が違ったのでめも.

elf/i386 の場合

(実行環境: Ubuntu 10.04LTS (linux 2.6.32), GNU assembler version 2.20.1 (i486-linux-gnu))


まず.シンボル間の足し算はできません(当然)

.data
a:
.byte 1
b:
.byte 2

z:
.long b+a
$ gcc -c -o a.o a.s
a.s: Assembler messages:
a.s:9: Error: invalid sections for operation on `b' and `a'

以下の演算はできます

.data
a:
.byte 1
b:
.byte 2
c:
.byte 3
d:
.byte 4

u:
.long a          # もちろんOK. R_386_32な再配置(aのアドレス)
x:
.long b - a      # OK. この場合は再配置は必要ない
y:
.long c - b - a  # OK. この場合は再配置が必要
$ gcc -c -o a.o a.s
$ objdump -r a.o
...
RELOCATION RECORDS FOR [.data]:
OFFSET   TYPE              VALUE
00000004 R_386_32          .data
0000000c R_386_PC32        *ABS*

最後のyは.dataセクションがロードされるアドレスを引く必要があるため,再配置が必要となります.実際の再配置種別的にはR_386_PC32であるので,yにはaddendとしてc-b-a+yの値が入っています.

$ objdump -D a.o
00000000 <a>:
   0:   01 02                   add    %eax,(%edx)

00000001 <b>:
   1:   02 03                   add    (%ebx),%al

00000002 <c>:
   2:   03 04 00                add    (%eax,%eax,1),%eax
...
0000000c <y>:
   c:   0d                      .byte 0xd            # y に入っている値は0x0d
   d:   00 00                   add    %al,(%eax)    # これはc-b-a+y

異なるセクション間のシンボルの引き算はできません

.text
a:
.byte 1

.data
b:
.byte 2

z:
.long b-a
$ gcc -c -o a.o a.s
a.s: Assembler messages:
a.s:10: Error: can't resolve `.data' {.data section} - `a' {.text section}

Mach-O/x86-64 の場合

(実行環境:Mac OS X 10.8,Apple Inc version cctools-836, GNU assembler version
1.38)


シンボルの足し算ができないのは同じです.

引き算は一つまで.

.data
a:
.quad 1
b:
.quad 2
c:
.quad 3

x:
.quad a         # もちろんOK.
                # X86_64_RELOC_UNSIGNED な再配置
y:
.quad b - a     # OK. mach-oでは再配置が必要
                # (X86_64_RELOC_SUBTRACTORとX86_64_RELOC_UNSIGNED)
% gcc -c -o a.o a.s
% otool -rv a.o
z.o:
Relocation information (__DATA,__data) 3 entries
address  pcrel length extern type    scattered symbolnum/value
00000020 False quad   True   SUB     False     a
00000020 False quad   True   UNSIGND False     b
00000018 False quad   True   UNSIGND False     a

3つの引き算はできません.

.data
a:
.quad 1
b:
.quad 2
c:
.quad 3

z:
.quad c - b - a # できない
% gcc -c -o z.o z.s
z.s:8:Expression too complex, 2 symbols forgotten: "b" "a"


異なるセクション間のシンボルの引き算はできます(!)

.text
a:
.quad 1

.data
b:
.quad 1

z:
.quad b-a
z:
% gcc -c -o z.o z.s
% otool -rv z.o
Relocation information (__DATA,__data) 2 entries
address  pcrel length extern type    scattered symbolnum/value
00000008 False quad   True   SUB     False     a
00000008 False quad   True   UNSIGND False     b


まぁ,だから何,という話ですが..