浮动到双倍(IEEE754)转换

时间:2017-12-30 18:58:17

标签: c assembly floating-point x86

我正在尝试在x86架构上的asm中将32位float转换为64位double。转换是由asm编写的函数完成的,然后我想从C调用它。我不知道我做错了什么,但是dst所指向的内存似乎保持不变并且在printf之后程序崩溃。 我想在没有任何浮点数据的情况下这样做。以下是代码:

.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

和C代码:

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

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

2 个答案:

答案 0 :(得分:2)

您的主要问题是访问参数。由于您pusha [ebp+8] [ebp+12][ebp+36]的参数不是而不是,而是[ebp+40]sudo docker commit CONTAINER_ID new_image_name 。调试器会立即向您展示。即使进行了这些更改,您的代码仍然会被破坏。

答案 1 :(得分:0)

好的,终于可行了。非常有帮助的是Jester关于args访问的建议。愚蠢的事情,但很难注意到。这是最终的代码:

.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