2016-04-24 84 views
1

我不明白爲什麼這段代碼不適合我。我需要使用scanf函數進行double操作,然後使用printf進行相同的操作。 使用此代碼時結果不好。我看到的是非常隨機的字符。ASM x64 scanf printf double,GAS

.data 

d1: .double 


format: .asciz "%lf\n" 
format2: .asciz "%lf" 

.text 
.globl main 

main: 

subq $8, %rsp 

#scanf 
movq $0, %rax 
movq $d1, %rsi 
movq $format2, %rdi 
call scanf 
addq $16, %rsp 

#printf 
movq $1, %rax 
movsd d1, %xmm0 
movq $format, %rdi 
call printf  
addq $16, %rsp 

#exit 
movq $1, %rdi 
xorq %rax, %rax 
call exit 
+2

調試,單步,看寄存器值。 –

+1

這可能不是問題所在,因爲'main'永遠不會返回,並且您從不讀取任何堆棧內存,但是在每次調用之後,您都會用'add $ 16,%rsp'打破堆棧。 '%rsp'是一個保存呼叫的寄存器,所以它在調用之後具有與之前相同的值。另外,你應該把'd1'放在bss中,而不是'.data'中,因爲你不需要在它的可執行文件中存儲一個值。其實這是問題。 –

+0

^^ lol,panto評論:'哦不,不是'....'哦,是的,它是' –

回答

1

這就是問題所在:

.data 
d1: .double  # declares zero doubles, since you used an empty list 
format: .asciz "%lf\n" 

d1format具有相同的地址,因爲.double與無參數組裝不了了之。 (「.double expects zero or more flonums, separated by commas. It assembles floating point numbers.」)。

因此scanf會覆蓋您用於printf的格式字符串。這是printf打印的隨機垃圾。

修正是實際保留一些空間,最好在bss中。 (This doc explains it well,即使它是一些具體的gcc端口)

相反,使用這樣的:

#.bss 
# .p2align 3 
# d1: .skip 8   ### This is the bugfix. The rest is just improvements 

# or just use .lcomm instead of switching to the .bss and back 
.lcomm d1, 8 

.section .rodata 
print_format: .asciz "%f\n"  # For printf, "%f" is the format for double. %lf still works to print a double, though. Only %llf or %Lf is long double. 
scan_format: .asciz "%lf"  # scanf does care about the trailing whitespace in the format string: it won't return until it sees something after the whitespeace :/ Otherwise we could use the same format string for both. 

.text 
.globl main 
main: 
    subq $8, %rsp 

    xor %eax,%eax 
    mov $d1, %esi   # addresses for code and static data are always in the low 2G in the default "small" code model, so we can save insn bytes by avoiding REX prefixes. 
    mov $scan_format, %edi 
    call scanf 

    mov $1, %eax 
    movsd d1, %xmm0 
    mov $print_format, %edi 
    call printf 

    add $8, %rsp 
    ret 

    #xor %edi,%edi # exit(0) means success, but we can just return from main instead. It's not a varargs function, so you don't need to zero rax 
    #call exit 

更多的東西有關編寫高效的彙編代碼,請參閱標籤維基鏈接。


而且會工作,但在浪費你的可執行8個字節:

.data 
d1: .double 0.0 
+0

非常感謝!當然這個代碼適合我。 – zderzak678