我使用高級語言,我試圖理解低級語言的層次結構。我知道不同的微處理器用不同的語言說話(如果我在這個假設中錯了,請糾正我),但是我們說他們說不同的二進制或彙編命令嗎?特定行的二進制代碼是否會在每個微處理器中執行相同的命令?
所有的二進制代碼是一樣的嗎?意思是一組二進制指令在每個CPU或微處理器上執行相同的命令嗎?
謝謝大家。我一直在研究這一點,我無法在任何地方找到明確的答案。
我使用高級語言,我試圖理解低級語言的層次結構。我知道不同的微處理器用不同的語言說話(如果我在這個假設中錯了,請糾正我),但是我們說他們說不同的二進制或彙編命令嗎?特定行的二進制代碼是否會在每個微處理器中執行相同的命令?
所有的二進制代碼是一樣的嗎?意思是一組二進制指令在每個CPU或微處理器上執行相同的命令嗎?
謝謝大家。我一直在研究這一點,我無法在任何地方找到明確的答案。
二進制是一種數字表示形式,以及十進制和十六進制。將代碼稱爲二進制是指使用晶體管等在硬件級別上表示CPU指令(機器代碼或object code)和諸如存儲器地址等數據的方式。
的CPU可以具有不同的instruction sets,如Intel的x86,ARM,MIPS等
以下爲x86-64的指令的示例由拆裝objdump
表示爲十六進制值:
$ objdump -dj .text test | grep -A12 "<main>:"
00000000004004f9 <main>:
4004f9: 55 push %rbp
4004fa: 48 89 e5 mov %rsp,%rbp
4004fd: 48 83 ec 10 sub $0x10,%rsp
400501: c7 45 f8 0a 00 00 00 movl $0xa,-0x8(%rbp)
400508: 8b 45 f8 mov -0x8(%rbp),%eax
40050b: 89 c7 mov %eax,%edi
40050d: e8 db ff ff ff callq 4004ed <test>
400512: 89 45 fc mov %eax,-0x4(%rbp)
400515: 8b 45 fc mov -0x4(%rbp),%eax
400518: c9 leaveq
400519: c3 retq
40051a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
operation codes and operands(中間列)的內存地址(最左邊一列)和十六進制值也可以用二進制或十進制表示(分別爲基址2和基址10)。我知道不同的微處理器用不同的語言進行對話(如果我在這個假設中我錯了,請糾正我),但是我們是在討論彙編語言還是二進制文件?彙編語言可以表示爲二進制值,也可以表示爲十六進制值(請參見上面的反彙編代碼),也可以表示爲人類可讀的mnemonics(上面最右邊一列)。
爲了使這更清楚,這裏是一個Intel x86 Assembler Instruction Set Opcode Table的快照:
均爲二進制代碼一樣嗎?意思是一組二進制指令在每個CPU或微處理器上執行相同的命令嗎?
可執行代碼必須以符合CPU指令集的方式表示。例如,MIPS處理器無法執行x86代碼,x86處理器無法執行MIPS代碼。沒有通用指令集。
沒有ARM執行ARM指令,MIPS處理器執行MIPS,等等。有許多不同的不兼容指令集。您可以使用的術語是機器碼或機器語言,它是二進制碼,是使處理器運行的位。彙編語言理想地是一對一可讀的助記符,一種比機器代碼更容易編程和讀取的文本語言。彙編程序使用匯編語言並將其轉換爲機器代碼。
所以採取這種簡單函數
unsigned char fun (unsigned char a, unsigned char b)
{
return(a+b+3);
}
的臂實現可能是
00000000 <fun>:
0: e2811003 add r1, r1, #3
4: e0800001 add r0, r0, r1
8: e20000ff and r0, r0, #255 ; 0xff
c: e12fff1e bx lr
機器代碼是0xe2811003部分和具有一對一的關係到該指令是彙編語言添加r1,r1,#3這個處理器有寄存器r0,r1,r2。這個編譯器符合一個約定,即第一個參數在r0中傳遞,第二個在r1中,所以a在r0中,而b在r1中,並且我們需要返回r0,所以我們將r1加3,然後我們加上r1現在是b + 3)到r0(這是a)並將其保存在r0中,所以r0現在保存a + b + 3,因爲這是unsigned char math,8位,我們需要並用0xFF保持結果爲無符號char,然後返回。
我說的一種方式,因爲與此相同的代碼和編譯器,我可以改變的編譯器選項,並得到
00000000 <fun>:
0: e52db004 push {r11} ; (str r11, [sp, #-4]!)
4: e28db000 add r11, sp, #0
8: e24dd00c sub sp, sp, #12
c: e1a03000 mov r3, r0
10: e1a02001 mov r2, r1
14: e54b3005 strb r3, [r11, #-5]
18: e1a03002 mov r3, r2
1c: e54b3006 strb r3, [r11, #-6]
20: e55b2005 ldrb r2, [r11, #-5]
24: e55b3006 ldrb r3, [r11, #-6]
28: e0823003 add r3, r2, r3
2c: e20330ff and r3, r3, #255 ; 0xff
30: e2833003 add r3, r3, #3
34: e20330ff and r3, r3, #255 ; 0xff
38: e1a00003 mov r0, r3
3c: e28bd000 add sp, r11, #0
40: e49db004 pop {r11} ; (ldr r11, [sp], #4)
44: e12fff1e bx lr
這是相同的未經優化的版本,它也實現了C代碼,我們要求它,它只是是...未優化...命令行上-O2和-O0之間的差異。
我們的簡單功能的x86版
0000000000000000 <fun>:
0: 8d 44 3e 03 lea 0x3(%rsi,%rdi,1),%eax
4: c3 retq
一個我喜歡扔在看到如果人們知道它是什麼
00000000 <_fun>:
0: 1166 mov r5, -(sp)
2: 1185 mov sp, r5
4: 9d40 0006 movb 6(r5), r0
8: 65c0 0003 add $3, r0
c: 9d41 0004 movb 4(r5), r1
10: 6040 add r1, r0
12: 1585 mov (sp)+, r5
14: 0087 rts pc
MSP430
00000000 <_fun>:
0: 1166 mov r5, -(sp)
2: 1185 mov sp, r5
4: 9d40 0006 movb 6(r5), r0
8: 65c0 0003 add $3, r0
c: 9d41 0004 movb 4(r5), r1
10: 6040 add r1, r0
12: 1585 mov (sp)+, r5
14: 0087 rts pc
和回手臂,手臂有一個16位指令集稱爲拇指
00000000 <fun>:
0: 3103 adds r1, #3
2: 1840 adds r0, r0, r1
4: 0600 lsls r0, r0, #24
6: 0e00 lsrs r0, r0, #24
8: 4770 bx lr
所以希望非常清楚的是,機器代碼絕不是通用的,事實上編譯器也沒有多種方法將相同的高級代碼編譯爲彙編語言。即使對於具有相同編譯器的相同目標。
注意我說編譯成彙編語言,這是一個非常普遍的做法,你已經有了一個彙編器和連接器,編譯到機器代碼很難讀,所以很難爲編譯器作者進行調試,沒有理由當你已經有一個彙編程序的時候這樣做。這就是爲什麼他們被稱爲工具鏈。很常見,當你運行gcc -o hello hello.c運行很多程序時,只有gcc cmopiler本身就是一些程序,爲了讓下一個程序保留臨時文件而執行,最後調用匯編程序(除非你指定-S並且它只是用匯編語言停止)將其組裝成一個對象,然後gcc清理臨時文件。再次相當普遍,這就是爲什麼它被稱爲工具鏈,編譯器彙編到鏈接器,鏈是一系列按順序運行的程序。
用GCC例如,如果我把--save-臨時工在命令行上
so.i
# 1 "so.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "so.c"
unsigned char fun (unsigned char a, unsigned char b)
{
return(a+b+3);
}
so.s
.cpu arm7tdmi
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 1
.eabi_attribute 30, 2
.eabi_attribute 34, 0
.eabi_attribute 18, 4
.file "so.c"
.text
.align 1
.p2align 2,,3
.global fun
.syntax unified
.code 16
.thumb_func
.fpu softvfp
.type fun, %function
fun:
adds r1, r1, #3
adds r0, r0, r1
lsls r0, r0, #24
lsrs r0, r0, #24
@ sp needed
bx lr
.size fun, .-fun
.ident "GCC: (GNU) 6.3.0"
,然後它使對象這是一個二進制文件,我們可以使用objdump來查看上面的內容。
是一個非常枯燥的程序/功能wasnt非常令人興奮的,但如果你有包含且有包括等等,這些中間的一個文件將與所有的包括所以真正展開了一個非常大的單個文件編譯器只需要在一個文件上工作。
也可能你知道成功,因爲在公司不會去,處理器familys隨着時間的推移8088/86至80186至80286,至80386至80486等等發展到現在。隨着x86我們從16位到32位到64位處理器,每次都增加新的東西,新的指令和其他功能。隨着ARM的發展,每一代都增加了指令,直到ARMv8成爲64位解決方案指令集的完整工具。 MIPS等。 –
通常它們會採用一種以前未定義的指令模式,並將其轉換爲指令或轉換爲可擴展到另一個指令池的前綴。因此,爲x86編譯的程序不僅不能在ARM上運行,而且可能無法在另一個x86上運行,如果它來自不同的一代或處於不同的模式。 –
大會僅僅是一個低級語言,人類的理解,真正的機器代碼是二進制的,你可以在一些組件轉換,然後,如果喜歡,你可以轉換到一些高級語言如C.
這裏一個將機器語言代碼(0x2237FFF1)轉換爲MIPS程序集的簡單示例。
0x2237FFF1 this in hexadecimal
二進制
0010 0010 0011 0111 1111 1111 1111 0001
現在我在讀操作碼(001000),並知道這是I型和 addi
指令
現在我的分組二進制成I型指令
op rs rt imm
001000 10001 10111 1111111111110001
8 17 23 -15
看看MIPS參考她並發現該指令必須是
addi $s7,$s1,-15
如果想繼續前進,您可以將其轉換爲C,它是一個簡單的加法。
答案對我來說似乎很清楚,例如,如果你看MIPS和x86,他們的機器代碼是完全不同的。 – harold
感謝哈羅德,我只是不清楚這些東西的大部分,並且仍然不確定像MIPS或IA-32這樣的語言實際上是機器代碼還是程序集。我沒有深入研究這一點,只是想掌握基本概念。 – alexr101
你可以找到答案,如果你查找指令集或機器代碼的各種處理器,你知道的名字。 –