2011-03-30 47 views
26

我是一名裝配編程的新手,在裝有GNU彙編程序v2.20.1的Ubuntu x86_64桌面上工作通過Programming Ground Upx86裝配pushl/popl不能與「錯誤:後綴或操作數無效」工作

我已經能夠組裝/鏈接執行我的代碼,直到我開始使用pushl/popl指令來操作堆棧。下面的代碼無法組裝:

.section .data # empty 

.section .text 
.globl _start 
_start: 
pushl $1  # push the value 1 onto the stack 
popl %eax  # pop 1 off the stack and into the %eax register 
int $0x80  # exit the program with exit code '1' 

使用 「爲test.s -o test.o」,出現在終端上這些錯誤並test.o不創建:

test.s: Assembler messages: 
test.s:9: Error: suffix or operands invalid for 'push' 
test.s:10: Error: suffix or operands invalid for 'popl' 

I」我檢查了文檔,我用pushl和popl的操作數是有效的。這不完全是一個調試問題 - 所以我的代碼有什麼問題?還是我的彙編程序?

+6

這看起來像32位代碼,但您正試圖組裝64位(x86_64上的默認設置)。傳遞適當的標誌以構建爲32位,例如'as -arch i386 ...' – 2011-03-30 11:14:57

+1

我相信Paul有正確的答案。你可能需要--32作爲。 – 2011-03-30 11:15:53

+1

我提到了我用來學習x86彙編的教科書(_Programming Ground Up_似乎是一個非常流行的免費教材) - 是否還有一個類似流行的x86/64位教程(免費並不重要)新手? 我意識到這可能是一個太大的問題在這裏問,但32位和64位作爲第一次使用匯編編程的經驗有什麼區別? – maxm 2011-03-30 15:16:03

回答

29

在64位模式下,您無法推送和彈出32位值;你需要pushqpopq

另外,您不會以這種方式得到正確的退出。在32位x86上,您需要將%eax設置爲1以選擇系統調用exit()%ebx設置爲您實際希望的退出代碼。在64位x86上(這就是你正在使用的),約定是不同的:exit()的系統調用號是60,而不是1;第一個系統調用參數進入%rdi,而不是%rbx;系統調用調用操作碼不是int $0x80,而是特殊的x86-64操作碼syscall

導致:

.section .data 
.section .text 
.globl _start 
_start: 
    pushq $60 
    popq %rax 
    pushq $1 
    popq %rdi 
    syscall 

(每個push/pop序列可以用一個簡單的mov(如mov $60, %eax)當然可以替代,我想那您要明確測試pushpop,優化代碼大小,或避免在機器代碼0字節(利用漏洞有效載荷))


相關:

+1

+1快10秒,更具體。 – hirschhornsalz 2011-03-30 12:08:14

+0

謝謝,你們兩個搖滾:)是的,我只是使用push/pop來展示問題,而不是重新發明mov。儘管我不知道x32和x64架構是一個問題。 – maxm 2011-03-30 15:05:49

+2

哪裏可以找到32/64之間差異的很好參考?即我可以使用什麼資源與本書一起編程64位? – FigmentEngine 2011-04-11 15:13:45

7

您需要

pushq $1  # push the value 1 onto the stack 
popq %rax  # pop 1 off the stack and into the %eax register 

注意更換推/彈出序列中的錯誤信息爲 「後綴或操作無效」,只有你在錯誤信息中檢查了邏輯OR的第二部分,可能是因爲你不完全確定w帽子後綴的意思是:它是「l」。

編輯:請參閱托馬斯答案解釋爲什麼即使它集合,你的代碼也無法工作。

+1

是的,我想我只是在精神上阻止了後綴部分bcs我不知道它的含義。謝謝澄清 – maxm 2011-03-30 15:28:55

12

最近,我開始過下面這些例子中,我發現了以下工作:

  1. 添加.code32到你的彙編代碼的頂部
  2. --32標誌裝配
  3. 鏈路與-m elf_i386標誌

你可以看我的例子here

+0

在32位指令中,用-m elf_i386標誌鏈接,程序可以正常運行。但如何使它在64位指令中工作? http://stackoverflow.com/questions/25401047/how-to-make-it-work-in-x86-64-assembly – sinceq 2014-08-20 09:52:25

+0

**你不需要'。code32',實際上應該避免它,所以你如果您忘記了其他兩個步驟並構建爲64位**,那麼在構建時會發出嘈雜的失敗**(來自像'push%eax'這樣的指令)**。所有'.code32'都可以讓你將32位機器代碼放在一個64位的可執行文件中,在那裏它將在運行時解碼爲「錯誤」。 (或者在.code16或.code32之後切換回32位)。如果這不是你想要的,不要使用它!另請參見[使用64位GNU工具構建32位可執行文件](https://stackoverflow.com/questions/36861903/assembling-32-bit-binaries-on-a-64-bit-system-gnu-toolchain) – 2017-11-27 06:12:16

2

我遇到了這個錯誤,通過同一本書工作。 我創建了下面的shell腳本(att.sh):

#!/bin/sh 
as --32 $1.s -o $1 
ld -melf_i386 $1.o -o $1 
./$1 
echo $? 

,然後我做的可執行文件和運行(假設輸入文件myfile.s的):

chmod +x ./att.sh 
./att.sh myfile 
-1

你可以按任意值,而不推命令等上堆 和彈出該

decq %rsp 
movb $0, (%rsp) 

推1個字節後

movb (%rsp), %al 
incq %rsp 

和其他任何大小。作爲編譯器不會產生任何錯誤,所有的工作都會很好!要解決可能使用rbp寄存器而不是rsp。現在是允許的。

+0

你完全錯過了這一點。 OP有32位代碼,並意外將其構建爲64位。他們*想*做一個32位的push來匹配'pop%eax'作爲一個3字節的方式來設置'eax = 1'。你的代碼需要'movzbl(%rsp),%eax'來做到這一點。另外,你通常不希望像這樣錯失'%rsp',因爲信號處理程序可以在任何時候運行。不,你不能總是使用'%rbp';使框架指針是可選的。 – 2017-11-27 06:06:03

+0

無論如何,OP不想避免'push' /'pop'。 '推$ 1'在64位模式下工作正常(作爲64位推送。) – 2017-11-27 06:06:31