[AMD64, linux, gas] Adresse ins Register

28/02/2010 - 14:00 von Markus Wichmann | Report spam
Hi all,

ich muss mich gerade mit gas auseinandersetzen (geht um die dietlibc).
Und dabei habe ich ein Problem festgestellt.

Ich habe vor ein paar Mathe-Funktionen zu schreiben. Infolge der
Unfàhigkeit von SSE, irgendwas nützliches tun zu können, ohne auf krude
Hacks zurückzugreifen, muss ich also den oder die Parameter aus der
SSE-Einheit in die FPU bewegen. Dafür habe ich eine Funktion
geschrieben (weil der Code ja für alle Funktionen gleich ist).

Dieser Code sieht so aus:

abi_wrapper_1arg_d:
sub $8, %rsp
movsd %xmm0, (%rsp)
fldl (%rsp)
call *%rax
fstpl (%rsp)
movsd (%rsp), %xmm0
add $8, %rsp
ret

Die eigentlichen Funktionen sehen dann so aus:

acos:
mov acosm, %rax
jmp abi_wrap_1arg_d

acosm:
fld %st0 /* x : x */
fmul %st0 /* x^2 : x */
fld1 /* 1 : x^2 : x */
fsubp /* x^2 - 1 : x */
fsqrt /* sqrt(x^2 - 1) : x */
fxch /* x : sqrt(x^2 - 1) */
fpatan /* acos x */
ret

So, ein kleiner Einblick. Problem ist jetzt, dass der Assembler dabei
irgendwas macht, aber nicht was er soll. Das Programm geht jedenfalls
mit einer Segmentation Fault baden. Und die entsteht bei

call *%rax

Aber wieso? Im Disassembler des fertig gelinkten Programms zeigt sich,
dass in rax auch der richtige Wert reingeschrieben wird. Hat dieser
Aufruf die falsche Syntax? Falls es nicht klar geworden ist, ich möchte
die Adresse der Instruktion hinter dem call auf den Stack pushen und
dann den Wert in rax nach rip verschieben.

Ich hànge mal das Disassembler-Listing (auf das wesentliche gekürzt) an:

lfs/work/dietlibc/x86_64/t: file format elf64-x86-64


Disassembly of section .text:

0000000000400144 <_start>:
400144: 5f pop %rdi
400145: 48 89 e6 mov %rsp,%rsi
400148: 57 push %rdi
400149: 48 8d 54 fe 08 lea 0x8(%rsi,%rdi,8),%rdx
40014e: 48 89 15 63 17 20 00 mov %rdx,0x201763(%rip) # 6018b8 <__bss_start>
400155: e8 0a 00 00 00 callq 400164 <main>
40015a: 48 89 c7 mov %rax,%rdi
40015d: e8 da 00 00 00 callq 40023c <_exit>
400162: f4 hlt
400163: 90 nop

0000000000400164 <main>:
400164: 55 push %rbp
400165: 48 89 e5 mov %rsp,%rbp
400168: f2 0f 10 05 58 14 00 movsd 0x1458(%rip),%xmm0 # 4015c8 <memmove+0x4c>
40016f: 00
400170: e8 17 00 00 00 callq 40018c <acos>
400175: bf c0 15 40 00 mov $0x4015c0,%edi
40017a: b8 01 00 00 00 mov $0x1,%eax
40017f: e8 e4 00 00 00 callq 400268 <printf>
400184: b8 00 00 00 00 mov $0x0,%eax
400189: c9 leaveq
40018a: c3 retq
40018b: 90 nop

000000000040018c <acos>:
40018c: 48 8b 04 25 aa 01 40 mov 0x4001aa,%rax
400193: 00
400194: e9 3e 00 00 00 jmpq 4001d7 <abi_wrap_1arg_d>

0000000000400199 <acosf>:
400199: 48 8b 04 25 aa 01 40 mov 0x4001aa,%rax
4001a0: 00
4001a1: e9 16 00 00 00 jmpq 4001bc <abi_wrap_1arg_f>

00000000004001a6 <acosl>:
4001a6: db 6c 24 08 fldt 0x8(%rsp)

00000000004001aa <acosm>:
4001aa: d9 c0 fld %st(0)
4001ac: dc c9 fmul %st,%st(1)
4001ae: d9 e8 fld1
4001b0: de e1 fsubp %st,%st(1)
4001b2: d9 fa fsqrt
4001b4: d9 c9 fxch %st(1)
4001b6: d9 f3 fpatan
4001b8: c3 retq
4001b9: 90 nop
4001ba: 90 nop
4001bb: 90 nop

00000000004001bc <abi_wrap_1arg_f>:
4001bc: 48 83 ec 04 sub $0x4,%rsp
4001c0: f3 0f 11 04 24 movss %xmm0,(%rsp)
4001c5: d9 04 24 flds (%rsp)
4001c8: ff d0 callq *%rax
4001ca: d9 1c 24 fstps (%rsp)
4001cd: f3 0f 10 04 24 movss (%rsp),%xmm0
4001d2: 48 83 c4 04 add $0x4,%rsp
4001d6: c3 retq

00000000004001d7 <abi_wrap_1arg_d>:
4001d7: 48 83 ec 08 sub $0x8,%rsp
4001db: f2 0f 11 04 24 movsd %xmm0,(%rsp)
4001e0: dd 04 24 fldl (%rsp)
4001e3: ff d0 callq *%rax
4001e5: dd 1c 24 fstpl (%rsp)
4001e8: f2 0f 10 04 24 movsd (%rsp),%xmm0
4001ed: 48 83 c4 08 add $0x8,%rsp
4001f1: c3 retq

Tschö,
Markus

Progress (n.): Process through which USENET evolved from smart people in
front of dumb terminals to dumb people in front of smart
terminals.

news://freenews.netfront.net/ - complaints: news@netfront.net
 

Lesen sie die antworten

#1 Jan Seiffert
28/02/2010 - 18:08 | Warnen spam
Markus Wichmann schrieb:
Hi all,

ich muss mich gerade mit gas auseinandersetzen (geht um die dietlibc).
Und dabei habe ich ein Problem festgestellt.



[snip]
So, ein kleiner Einblick. Problem ist jetzt, dass der Assembler dabei
irgendwas macht, aber nicht was er soll. Das Programm geht jedenfalls
mit einer Segmentation Fault baden. Und die entsteht bei

call *%rax

Aber wieso?



Was ich auch nicht so ganz verstehe...

Im Disassembler des fertig gelinkten Programms zeigt sich,
dass in rax auch der richtige Wert reingeschrieben wird.



Nein

Hat dieser Aufruf die falsche Syntax?



Ich denke nicht, denn...

000000000040018c <acos>:
40018c: 48 8b 04 25 aa 01 40 mov 0x4001aa,%rax
400193: 00



... das ist so unsinn.
Du bewegst nicht die Konstante 0x4001aa nach rax, sondern du versuchst hier von
der Addresse 0x4001aa ein qword nach rax zu laden.

Konstanten haben in gas ein $ davor, addressen sind nackt.
Richtig waere:
mov $0x4001aa, %rax
jmpq abi_wrap_1arg_d

[snip]
So und dazu noch ein kleines "Achtung":
Als lib moechtest du "position independent code" benutzen, das spart relocations
und ermoeglicht das der Kernel die Speicherseiten (grade fuer sowas wie die
libc) besser sharen/file back'ed machen kann.
Auf x86_32 ist das ein PITA, aber auf x86_64 ist das dank rip-relative addresing
einfach.
Das sieht dann ungefaehr so aus (ungetested):
acos:
lea acosm(%rip), %rax
jmp abi_wrap_1arg_d

So kann gas den konstanten _Abstand_ zwischen dem lea und dem Symbol acosm in
das lea eincoden. Zur Laufzeit kommt das dann richtig raus, egal wo der Kernel
die libc grade hingemappt hat.

Die ABI auf x86_64 schreibt AFAIK auch PIC vor.

(Nebenhinweiss: Das AMD endlich rip-relative addressing eingebaut hat ist echt
"geil", aber es waere nicht x86 wenn da nicht noch ein fuckup drin waere: mit
%rip kannst du nicht alle Addressmodie benutzen (index & scale geht nicht))

Tschö,
Markus



Gruss
Jan

Woo Hoo Woo Hoo Hoo

Ähnliche fragen