2014-09-05 3 views
0

scanf을 사용하여 4 개의 부동을 입력하려고하면 스택에 저장하고 vmovupd을 사용하여 레지스터에 복사합니다. 내 문제는 그 4 개의 숫자를 출력하려고 할 때입니다. 프로그램의 오류는 printf입니다.printf의 분할 오류 - NASM 64 비트 Linux

나는 그것이 스택과 함께한다고 가정하지만, 여러 번 (한 번에 여러 명령어) 터지는 것을 시도해 보았다. 나는 여전히 어셈블리 코딩에 익숙하지 않기 때문에 gdb을 사용하면 나에게 너무 진보적이다.

debug이라는 파일이 포함되어 있습니다. 그것은 제가 레지스터와 스택을 볼 수있게합니다. (그 이유는 dumpstack입니다.) 그건 교수님이 제공 한 것이지 만 도움이되지는 않았지만 분명히 충분하지 않았습니다.

#include <iostream> 

using namespace std; 

extern "C" double ComputeElectricity(); 

int main() 
{ 
    cout << "Welcome to electric circuit processing by Chris Tarazi." << endl; 

    double returnValue = ComputeElectricity(); 

    cout << "The driver received this number: " << returnValue << endl; 

    return 0; 
} 

을 그리고 여기 ASM 코드입니다 :

다음은 .cpp

%include "debug.inc" 

extern printf 

extern scanf 

global ComputeElectricity 

;---------------------------------Declare variables------------------------------------------- 

segment .data 

greet db "This progam will help you analyze direct current circuits configured in parallel.", 10, 0 

voltage db "Please enter the voltage of the entire circuit in volts: ", 0 

first db "Enter the power consumption of device 1 (watts): ", 0 

second db "Enter the power consumption of device 2 (watts): ", 0 

third db "Enter the power consumption of device 3 (watts): ", 0 

fourth db "Enter the power consumption of device 4 (watts): ", 0 

thankyou db "Thank you. The computations have completed with the following results.", 10, 0 

circuitV db "Curcuit total voltage: %1.18lf v", 10, 0 

deviceNum db "Device number:    1     2     3     4", 10, 0 

power db "Power (watts): %1.18lf %1.18lf %1.18lf %1.18lf", 10, 0 

current db "Current (amps): %1.18lf %1.18lf %1.18lf %1.18lf", 10, 0 

totalCurrent db "Total current in the circuit is %1.18lf amps.", 10, 0 

totalPower db "Total power in the circuit is %1.18lf watts.", 10, 0 

bye db "The analyzer program will now return total power to the driver.", 10, 0 

string db "%s", 0 

floatfmt db "%lf", 0 

fourfloat db "%1.18lf %1.18lf %1.18lf %1.18lf", 0 

;---------------------------------Begin segment of executable code------------------------------ 

segment .text 

dumpstack 20, 10, 10 

ComputeElectricity: 

;dumpstack 30, 10, 10 

;---------------------------------Output greet message------------------------------------------ 

    mov qword rax, 0 
    mov rdi, string 
    mov rsi, greet 
    call printf 

;---------------------------------Prompt for voltage-------------------------------------------- 

    mov qword rax, 0 
    mov rdi, string 
    mov rsi, voltage 
    call printf 

;---------------------------------Get voltage-------------------------------------------------- 

    push qword 0 
    mov qword rax, 0 
    mov rdi, floatfmt 
    mov rsi, rsp 
    call scanf 
    vbroadcastsd ymm15, [rsp] 
    pop rax 

;---------------------------------Prompt for watts 1-------------------------------------------- 

    mov qword rax, 0 
    mov rdi, string 
    mov rsi, first 
    call printf 

;---------------------------------Get watts 1--------------------------------------------------- 

    push qword 0 
    mov qword rax, 0 
    mov rdi, floatfmt 
    mov rsi, rsp 
    call scanf 

;---------------------------------Prompt for watts 2-------------------------------------------- 

    mov qword rax, 0 
    mov rdi, string 
    mov rsi, second   
    call printf 

;---------------------------------Get watts 2--------------------------------------------------- 

    push qword 0 
    mov qword rax, 0 
    mov rdi, floatfmt 
    mov rsi, rsp 
    call scanf 

;---------------------------------Prompt for watts 3-------------------------------------------- 

    mov qword rax, 0 
    mov rdi, string 
    mov rsi, third  
    call printf 

;---------------------------------Get watts 3--------------------------------------------------- 

    push qword 0 
    mov qword rax, 0 
    mov rdi, floatfmt 
    mov rsi, rsp 
    call scanf 

;---------------------------------Prompt for watts 4-------------------------------------------- 

    mov qword rax, 0 
    mov rdi, string 
    mov rsi, fourth 
    call printf 

;---------------------------------Get watts 4--------------------------------------------------- 

    push qword 0 
    mov qword rax, 0 
    mov rdi, floatfmt 
    mov rsi, rsp 
    call scanf 

    ;dumpstack 50, 10, 10 

;---------------------------------Move data into correct registers------------------------------ 

    vmovupd ymm14, [rsp]    ; move all 4 numbers from the stack to ymm14 

    pop rax 
    pop rax 
    pop rax 
    pop rax 

    ;dumpstack 55, 10, 10  

    vextractf128 xmm10, ymm14, 0  ; get lower half 
    vextractf128 xmm11, ymm14, 1  ; get upper half 

;---------------------------------Move data into low xmm registers------------------------------ 

    movsd xmm1, xmm11     ; move ymm[128-191] (3rd value) into xmm1 
    movhlps xmm0, xmm11     ; move from highest value from xmm11 to xmm0 

    movsd xmm3, xmm10 
    movhlps xmm2, xmm10 

    ;showymmregisters 999 

;---------------------------------Output results------------------------------------------------- 

    ;dumpstack 60, 10, 10 

    mov rax, 4 
    mov rdi, fourfloat 
    push qword 0 
    call printf 
    pop rax 

ret 
+0

단순히 'printf'를 호출하는 'C'프로그램을 작성하고 어셈블리 목록을 생성 한 다음 해당 목록에서 컴파일러가 어떻게 수행하는지 배우십시오. – PaulMcKenzie

+0

@PaulMcKenzie 당신이 그것을보고 올바른 방향으로 나를 가리킬 수 있다면 [this] (http://goo.gl/WwIITD)를 생성했습니다. 나는 아직도 그것이 일어나고있는 이유를 알 수 없다. – ctzdev

+1

사람들이 컴파일러가 생성 한 코드를 연구하는 것을 계속 주장하는 것을 당황스럽게 생각한다. 리버스 엔지니어링은 거의 가장 어려운 가장 복잡한 작업이며, 특히 컴파일러가 생성 한 코드에서 잘못된 결론을 신속하게 이끌어 낼 수 있습니다. 대신, 관련 문서 (ABI 및 명령어 세트)를 읽고 디버거를 사용하십시오. – Jester

답변

3

문제는 당신의 스택 사용과입니다. 먼저 ABI 문서 위임 rsp을 16 바이트 정렬로 유지해야합니다. call은 스택에 8 바이트의 반환 주소를 넣기 때문에 rsp을 16의 더하기 8을 조정해야합니다. printf은 정렬되지 않은 주소에 대해 오류가있는 SSE 정렬 명령을 사용하기 때문에 segfault의 직접적인 원인입니다.

값을 계속 입력했지만 계속 팝하지 않기 때문에 스택이 여전히 불균형합니다. 스택으로 무엇을하고 싶은지 이해하기 어렵습니다.

일반적인 방법은 함수의 시작 부분 (프롤로그)에서 지역 주민을위한 공간을 할당하고 끝 부분 (에필로그)에서 이것을 비우는 것입니다. 위에서 설명한대로이 값은 16을 더한 8의 배수 여야합니다.

+0

프롤로그에서'align 16'을 실행하고'rsp'를 16 + 8의 배수로 조정해야합니까? 조정 부분이 아니라 조절 부분을 이해합니다. 제발 좀 더 자세히 설명해 주시겠습니까? 또한, 내가 스택에서 한 것은 스택에 4 개의 값을 넣었고'vmovupd'가 그 4 개의 값을 가져 와서'ymm14'에 넣었습니다. 거기에서 나는 무엇을 해야할지 잘 모릅니다. – ctzdev

+0

'align'은 어셈블리/링크 할 때 코드와 데이터를 정렬하기위한 것입니다. 필자가 의도 한 것은'rsp'를 정렬 된 상태로 유지하는 것이 었습니다. 16을 더한 8의 배수로 조정하면됩니다. 스택에 물건을 놓았지만 제거하지는 않았습니다. – Jester

+0

Nevermind. 내 교수 코드가 등록기에 문제를 일으키는 것 같아. 그러나 스택에서 4 가지 값을 이동 한 후 4 번 팝했습니다. 그런 다음'printf' 다음에'push qword 0'을 추가 한 다음'printf' 다음에'pop rax'를 추가했습니다. – ctzdev