2016-06-09 2 views
1

어셈블러에서 64 비트 값을 반환하려면 어떻게합니까?어셈블리 64 비트 : 이중 값을 반환하는 방법?

C 프로그램 :

#include <stdio.h> 

double result=0; 
double a = 10; 
extern double func(double a); 

int main() {  
    result = func(a); 
    printf("result: %f\n", result);  
    return 0; 
    } 

어셈블리 : 나는이 시도

 section .bss 
     x: resq 1 

     section .text 

     global func 

     func: 

     movq qword[x],xmm0 
     fld qword [x] 
     fld qword [x] 
     fadd 
     movq xmm0,qword[x] 

     ret 

그것은 20.0을 반환해야을하지만, 대신 내가 뭘 잘못했는지 항상 10.0 입니까?

+3

결과를 저장하지 마십시오. 그리고 아마도 x87 대신 SSE를 사용하는 것이 더 간단 할 것입니다. – ElderBug

+0

엘더 버그가 맞습니다. 'fadd'는'st (0)'에 값을 저장하는 st (0)과 st (1)을 추가했습니다. [x]의 값을 스택 맨 위에있는 값으로 업데이트하지 마십시오. 반환하기 전에 FPU 스택에서 여분의 값을 팝하지 마십시오 (이 함수를 5 번 호출하면 FPU 스택 오버 플로우 문제가 발생합니다). 연장자가 지적한대로 FPU 대신 SSE를 사용할 수 있습니다. 주어진 과제가 당신에게 이렇게하도록 요구하지 않는 한. –

+0

코드가 단순화 될 수도 있지만 32 비트 또는 64 비트 코드로 컴파일하는 것이 궁금합니다. 내가 얻은 결과로 가정하면 실행 파일은 64 비트가 될 것입니다. –

답변

2

게시 된 코드에는 의견이 없습니다. ... 그것은 OP 도움 것이다 언급, 그래서

movq qword[x],xmm0 ; Store current value in memory [Why?] 
fld qword [x]  ; Load current value from memory [Why??] 
fld qword [x]  ; Load current value from memory again 
fadd    ; Add top two stack items 
movq xmm0,qword[x] ; Read value from memory 

@ElderBug은 영업 이익은 최종 movq을하기 전에 메모리에 fadd의 결과를 저장하는 것을 잊었다 지적했다.

는 @Michael 페치는 전체 기능이 될 수 있다고 지적 많은 다음 코드를 사용하여보다 효율적 : @Michael 페치가 계속

addsd xmm0, xmm0 ; Add input parameter to itself 
ret    ; Done! 

가 원래의 코드는 '파편'많은 양의 왼쪽 점에 유의하기 부동 소수점 스택에 - pop 버전의 지침 (fstp 또는 faddp 대신 fadd)을 사용하여 정리하려고 시도하지 않았습니다. 이렇게하면 다음 부동 소수점 함수에 필요한 공간이 줄어들어 결국에는 부동 소수점 스택 오버플로가 발생합니다.

2

FPU와 XMM 계산을 혼용 할 수 없습니다. FPU에서 무언가를 계산할 때는 메모리에 @Elderbug가 말한대로 저장해야하며 Win OS에서 x64의 64 비트 procs로 반환하려면 XMM 레지스터에로드해야합니다. 64 비트 시스템에서 FPU를 사용할 수 있다는 장점이 있습니다. FPU의 내부 정밀도가 80bits 일 수 있습니다 (올바른 FPU를 사용하는 경우 제어 비트 : 비트 8,9 float32 (24 비트 가수) = 00b double float (53 비트 가수) = 10B 확장 정밀도 (64 비트 가수) = 11B

당신은 FPU 사용하려면 :

fld QWORD PTR x ; laod var to FPU: into ST(0) (MASM Syntax) 
fadd ST(0), ST(0) ; this adds [x]+[x] 
fstp QWORD PTR x ; store result back in var 
movsd xmm0, QWORD PTR x 

참고 :. 항상 SSE2가 (SSE1 기계에 요구되는 movsd를 들어 GP 오류가 발생합니다. 참조하십시오 인텔 ® 64 및 IA-32 아키텍처 소프트웨어 개발자 설명서 http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html Howeve r, Windows8/8.1/10을 실행하면 OS 자체가 시스템 요구 사항으로 SSE2를 요청하게됩니다.

편집 : SSE2는 x86-x64의 기준선이며 코멘트에 Peter Cordes가 명시한 바와 같이 64 비트에서 항상 사용할 수 있습니다.

당신이 XMM 레지스터와 SIMD를 사용하려면 :

movsd xmm0, QWORD PTR x 
addsd xmm0, xmm0 ; this instruction also requires SSE2 
; ok, retun xmm0 

또한 당신은 또한 XMM 및 MMX-레지스터를 혼합 할 수 없습니다 것을주의! (지침 MOVQ2DQ 및 MOVDQ2Q는 하나에서 다른 변환 할 수 있지만, 다른 사람은 할 수 없습니다)

함수 매개 변수를 사용하는 경우 그것은 Windows 운영 체제에서 실행해야합니다, 당신은 올바른 함수 프롤로그를 확인해야합니다/발문.참조 : https://future2048.blogspot.com

+0

x86-64는 SSE2를 기준으로 사용합니다. SSE1 경고는 32 비트 코드에서이 작업을 수행하는 경우에만 적용됩니다. (SSE2가없는 머신에서 실행될 수있는 코드에서 xmm regs에 double을 반환하는 호출 규칙을 사용하지 않아야합니다. 그러나 SSE1 만 사용하려는 경우 [http : //www.felixcloutier.com/x86/MOVLPS.html), 상위 64 비트를 0으로 설정하는 대신 레지스터의 이전 내용과 병합하기 때문에 그렇지 않습니다. (xmm 레지스터의 이전 값에 대한 false 의존성)) –

+0

또한 re : x87 정밀 컨트롤의 초기 설정 : [FP에 대한 Bruce Dawson의 우수 기사 시리즈] (https://randomascii.wordpress.com/2012/03/21/intermediate-floating-point -정도/). VC++의 CRT 코드는 적어도 32 비트 실행 파일의 경우 x87 장치를 53 비트 가수 정밀도로 설정합니다. 나는 그것이 혼자 남을 때 전체 기사를 다시 읽지 않았습니다. 그리고 저는 directx가 x87 precision을 바꾸는 것에 대해 읽은 것 같습니다. 그래서 저는 Windows를 사용하지 않아서 다행입니다. :) –

관련 문제