2017-12-30 50 views
0

Ich versuche 32bit float in 64bit double in Asm auf x86-Architektur zu konvertieren. Die Umwandlung erfolgt durch eine in asm geschriebene Funktion und dann möchte ich sie von C aus aufrufen. Ich habe keine Ahnung, was ich falsch mache, aber der Speicher von dst scheint unberührt zu bleiben und nach printf stürzt das Programm ab. Ich möchte es ohne irgendwelche Gleitkommaanweisungen tun. Hier ist der Code:float to double (IEEE754) Umwandlung

.686 
.model flat 
public _conv 

.data 
mantissa_mask dd 00000000011111111111111111111111b 
exponent_mask dd 01111111100000000000000000000000b 

.code 

_conv PROC 
pusha 
mov ebp, esp 

mov esi, dword ptr [ebp+8] ; src 
mov edi, dword ptr [ebp+12]; dst 

mov dword ptr [edi], 0 
mov dword ptr [edi+4], 0 

mov eax, dword ptr [esi] 
and eax, dword ptr mantissa_mask 
mov dword ptr [edi], eax 
xor edx, edx ; zero edx 
mov ecx, 1 
shl ecx, 29 ;ecx == 2^29 
mul ecx ;so it's like `shl edx:eax, 29` 
mov dword ptr [edi], eax 
mov dword ptr [edi+4], edx 

mov eax, dword ptr [esi] 
and eax, dword ptr exponent_mask 
shr eax, 23 ;put exponent on lowest bits 
sub eax, 127 ;exponent in float is coded enlarged by 127 
add eax, 1023 ;in double it's enlarged by 1023 
shl eax, 20 ;exponent in double starts on 20bit of 2nd byte 
or dword ptr [edi], eax 

;sign bit: 
bt dword ptr [esi], 31 
jc set_sign_bit 
    btr dword ptr [edi+4], 31 
    jmp endthis 
set_sign_bit: 
    bts dword ptr [edi+4], 31 
endthis: 

popa 
ret 
_conv ENDP 

END 

Und der C-Code:

void conv(float * src, double * dst); 

int main() 
{ 
    float src = 4.5f; 
    double dst = 0.; 
    conv(&src, &dst); 
    printf("%f\n", dst); 
    return 0; 
} 
+0

Stellen Sie sicher, dass Sie nicht versehentlich als 64-Bit kompilieren. Stellen Sie auch 'dst' auf ungleich Null, damit Sie prüfen können, ob es tatsächlich berührt wurde. Und verwenden Sie wie immer einen Debugger. – Jester

+2

Sie sollten etwas debuggen. –

+0

@Jester Ich hatte einige Bugs, die ich gerade gefunden habe. Entschuldigung dafür, ich habe Code in der Frage bearbeitet. – Criss

Antwort

0

Ok, endlich funktioniert es. Sehr hilfreich war der Rat von Jester über den Zugang zu Argumenten. Dummes Ding, aber schwer zu bemerken. Hier ist der endgültige Code:

.686 
.model flat 
public _conv 

.data 
mantissa_mask dd 00000000011111111111111111111111b 
exponent_mask dd 01111111100000000000000000000000b 

.code 

_conv PROC 
pusha 
mov ebp, esp 

;+36 and +40 since pusha 
mov esi, dword ptr [ebp+36]; src 
mov edi, dword ptr [ebp+40]; dst 

mov dword ptr [edi], 0 
mov dword ptr [edi+4], 0 

;mentissa: 
mov eax, dword ptr [esi] 
and eax, dword ptr mantissa_mask 
mov dword ptr [edi], eax 
xor edx, edx ; zero edx 
mov ecx, 1 
shl ecx, 29 ;ecx == 2^29 
mul ecx ;so it's like `shl edx:eax, 29` 
mov dword ptr [edi], eax 
mov dword ptr [edi+4], edx 

;exponent: 
mov eax, dword ptr [esi] 
and eax, dword ptr exponent_mask 
shr eax, 23 ;put exponent on lowest bits 
sub eax, 127 ;exponent in float is coded enlarged by 127 
add eax, 1023 ;in double it's enlarged by 1023 
shl eax, 20 ;exponent in double starts on 20bit of 2nd byte 
or dword ptr [edi+4], eax 

;sign bit: 
bt dword ptr [esi], 31 
jc set_sign_bit 
    btr dword ptr [edi+4], 31 
    jmp endthis 
set_sign_bit: 
    bts dword ptr [edi+4], 31 
endthis: 

popa 
ret 
_conv ENDP 

END 
2

Ihr Hauptproblem die Argumente zugreift. Da Sie pusha getan haben, sind die Argumente nicht bei [ebp+8] und [ebp+12], eher bei [ebp+36] und [ebp+40]. Ein Debugger hätte dir das sofort gezeigt. Selbst mit diesen Änderungen ist Ihr Code jedoch immer noch fehlerhaft.

+0

Oh, danke dafür über' pusha'. Habe das komplett nicht bemerkt. Mit einigen Bugfixes (ich habe eine Bearbeitung des fraglichen Codes gemacht) und der Änderung von Argumenten, die darauf zugreifen, stürzt nicht ab, sondern gibt 0 aus. Bitte schauen Sie sich den Code noch einmal an, da es eine Bearbeitung gab. – Criss