macOS 汇编指南
現在很多匯編的學習資料、途徑和工具都是關于 Windows 下的,所以這里來介紹一下 macOS 上學習使用匯編需要的資料和工具。
本文持續更新中,也是作為個人筆記來使用的。
為什么需要學習匯編(使用途徑)
匯編是計算機的“魔法”,雖然做個只會高級語言的“戰士”也可以,但是當給“武器”附魔之后,戰斗力也會大大增加(當然也有“玩火自焚”的)。
在現代,學習匯編之后的使用途徑有幾種:
- 直接用匯編指令寫程序的代碼,然后使用匯編器(Assembler)匯編成程序(這種學習的過程中可能使用比較多,在實際情況下很少用,因為太復雜了)。
- 用在 C 語言代碼中,提高性能和速度,或者實現一些特別的功能。例如 UNIX 和 Linux 中的匯編代碼就是為了提高運行速度,不然完全可以用純 C 語言寫出來;還有蘋果不讓開發者 iOS 平臺獲取 CPU 頻率之后,一些開發者通過在 Objective-C 代碼中使用匯編指令來推測頻率。
注1:不過蘋果后來加了轉換,讓推測的結果很不準,讓這種 app 徹底完犢子了。
注2:Objective-C 是 C 語言的一個超集,就像 C++ 也是 C 語言的一個超集,它們都屬于 C 語言家族。在蘋果推出 Swift 之前,蘋果平臺的開發全靠 Objective-C。
- 能看懂反編譯出來的內容(這種一般常規程序員用不到)。
不過在現在,匯編并不是編程的門檻,而是通往高手的必修課。但是新手還是建議先學會 C 語言再接觸匯編(這里的學會是指能看明白各種結構即可)。
相關資料推薦
在現在各種高級語言、腳本語言遍地開花的今天,匯編語言越來越不受歡迎,因為繁瑣、復雜,學習成本極高。例如, Intel CPU 開發手冊就有 5000 頁(每次發新的 CPU 之后都會更新,或增或減)。
第一個推薦的是蘋果官方的匯編指南:《Mac OS X Assembler Guide》,下載地址在這里。
這本指南包含了 Mac OS X 匯編器as的使用,匯編指令和地址模式的介紹等內容。
需要注意的是,它不光包括了 Intel CPU 的匯編內容,還包括更早期的 Power PC 的匯編內容。
但是由于該指南最新版本是 2005 年的,Intel 的指令有了巨大的更新,例如 AVX 等。并且蘋果也已經在轉向自己的 M1 芯片了(有意思的是,OS X 的匯編器手冊最新更新時間是 2020 年6月23日,而這就是 M1 更新的日子,不知道蘋果會不會在穩定之后再次更新)。
第二個推薦的是 Intel 的 《Introduction to x64 Assembly》,這是一篇匯編快速入門。新手可以看看,干貨濃度極高。
第三個是:Intel 的開發手冊。
這個手冊雖然很長,但是一個很不錯的資料,而且更新頻率很高,如果需要了解新的 Intel 指令,那么這就是必須要看的了。所以這篇屬于經常需要翻閱的。當然如果想見識見識也可以看看。鏈接是:Intel 64 和 IA-32 處理器相關的文檔
可以直接下載合訂本當作存檔,不過這樣不方便閱讀。(關于這個,曾經 Intel 可以免費提供紙質版,只要你發郵件提供地址即可,有不少人定,不過大多都墊了顯示器或者吃灰了。現在 Intel 不提供這個福利了,挺可惜的)
第一卷是一些大致的介紹,以及 Intel CPU 發展歷程和區別,如果是初學者可以瞅瞅;第二卷開始就是指令的介紹了。第2卷的日常使用率比較高,需要經常查閱。具體區別在之前的鏈接中的界面可以看到。
這里需要注意的是,雖然常說 Intel 擠牙膏,但是 Intel 幾乎每一代都會有指令、寄存器的更新和更改。所以文檔的更新頻率比較高,如果你需要使用最新的指令,那么請及時更新自己存儲的文檔。
第四個是一組關于 ARM 匯編的文檔。
首先因為 Mac 現在以及轉向自研的 M1 芯片了,M1 芯片是 ARM 架構的。
其次因為 ARM 現在并不像 Intel 一樣提供了匯編指南《ARM ? DeveloperSuite Assembler Guide
Version 1.2》(這篇指南最新的b版本是2001年的),而是分散開了。如果想入門,閱讀這本2001年的指南即可。
如果想深入了解最新的指令,那么查看這里https://developer.arm.com/architectures/instruction-sets。
匯編器以及實用工具介紹
匯編器(Assembler)和編譯器(Complier)是不同的。如果搞不明白的話,可以簡單理解成匯編器是將匯編指令轉換成程序的;編譯器是將高級語言的代碼(例如 C/C++、Java 等的代碼)轉換成程序的。
這里介紹一下匯編器以及可能用得到的實用工具們(包括編輯器)。
as:
Mac OS X 的匯編器,需要在“終端”中使用,類似于 Windows 的 masm。支持 Intel 處理器的匯編以及 Power PC 處理器的匯編。放在/usr/bin/as目錄下。在《Mac OS X Assembler Guide》中有使用方法的介紹。
ld:
連接器。
clang:
clang 有個狀態就是匯編器,而且可以 C 語言等代碼預處理成匯編語言代碼,詳細操作請看這里《clang 如何產生匯編代碼文件》。使用 clang 可能對你更方便,不過需要自己判斷了。
gcc:
gcc 和 clang具體區別這里不贅述,gcc 有個選項:-nostartfiles,使用這個命令可以直接忽略被鏈接的標準庫文件和初始化行為。這是因為有時候會出現不需要連接 C 標準庫,直接匯編即可,那么就需要這樣。最后會有相關演示。
size:
輸出對象文件的各部分大小,如下:
otool:
查看某部分大小和內容,類似 Windows 中的 debug.exe。例如查看__TEXT,__text部分的內容:
我們也可以使用otool來查看其他部分的內容,用以下命令格式:
clang 或 gcc:
Mac OS X 上,默認的 C、C++、Objective-C 編譯器。如果在“終端”里使用命令cc,那么會調用 clang,而不是 gcc。
Xcode:
蘋果自己的 IDE,有圖形界面,也有一些終端命令行工具,可以編寫 C、C++、Objective-C 和 Swift 語言的程序。可以利用 Xcode 來編寫含有匯編代碼的程序和 App。
語法區別
很多人可能對匯編有所了解,但可能都是基于 Windows 的。但是在 Mac OS X 或者 C 語言(這里 C 語言編譯器是 clang)內嵌匯編語言的語法中是不一樣的,這里來說一下:
1. 寄存器寫法
事先聲明一下,如果不是用as匯編,而是在 C 語言中或者其他情況下使用 clang 或者 gcc 來處理,那么不用管這條內容。
在 Windows 和 C 的匯編語法中,寄存器的名稱是直接寫的,例如mov ax,2。但是在as中,為了不與標識符(identifier,其實就是常說的變量)搞混,需要在寄存器前加上百分號%,例如mov %ax,2。并且所有的寄存器都得寫成小寫字母,不能像 Windows 或 C 里一樣不分大小寫。
十六進制寫法
在 Windows 中,十六進制被寫成以H或h結尾的,例如5c0dH。但是在 Mac OS X 中,需要寫成0x開頭的,例如0x1234。而在 C 語言中,二者皆可。
來用匯編寫一個 Hello World 吧!
寫代碼
最后會給出完整代碼,現在先分步講解。
首先新建一個名為helloworld.s的文件,匯編代碼文件的后綴一般是.asm或者.s。這時候就可以來寫第一部分的內容啦。
先是需要指明第一部分是——可執行命令:
然后指明創建的目標平臺:
.build_version macos, 12, 0 sdk_version 12, 1然后新建一個外部符號名稱_main用作程序的入口,就像 C 語言程序必須要有main()函數一樣。注意這里的下劃線不可以省略。
.globl _main ## -- Begin function main然后使用對齊(align)命令將位置計數器移到下一個邊界4, 0x90(一般來說都是地址)。
.p2align 4, 0x90然后我們就可以開始寫_main部分包含的內容啦,也就是開始寫main()函數了:
_main: ## @main.cfi_startproc ##表示函數的開頭。會初始化一些內部的數據結構,發出架構依賴的初始CFI 指令 ## %bb.0:pushq %rbp.cfi_def_cfa_offset 16.cfi_offset %rbp, -16movq %rsp, %rbp.cfi_def_cfa_register %rbpsubq $16, %rspmovl $0, -4(%rbp)leaq L_.str(%rip), %rdimovb $0, %alcallq _printfxorl %eax, %eaxaddq $16, %rsppopq %rbpretq.cfi_endproc ##結束函數這部分包含一些 cfi 相關的指令,可以在這里看到:https://web.mit.edu/rhel-doc/3/rhel-as-en-3/cfi-directives.html
此外,CFA是規范框架地址(Canonical Frame Address),相關資料可以看這里:
https://www.keil.com/support/man/docs/armasm/armasm_dom1361290010153.htm
接下來開始第二部分——可執行命令包含的字符串:
.section __TEXT,__cstring,cstring_literals L_.str: ## @.str.asciz "hello world!\n"這里就是準備輸出的字符串:hello world!\n了。
如果這里使用的是.ascii命令,那么這行應該改成.asciz "hello world!\n\0"。
因為.asciz自動補上了字符串末尾的\0,如果被用于 C 程序的話,就使用這個。
最后我們可以加上這么一行:
.subsections_via_symbols這行命令會告訴靜態連接編輯器,這部分對象文件(object file)能被分割成幾塊。不過這里用不用無所謂,不影響結果。但是出于嚴謹可以加上。
完整代碼如下:
.section __TEXT,__text,regular,pure_instructions.build_version macos, 12, 0 sdk_version 12, 1.globl _main ## -- Begin function main.p2align 4, 0x90 _main: ## @main.cfi_startproc ## 表示函數的開頭。會初始化一些內部的數據結構,發出架構依賴的初始CFI 指令 ## %bb.0:pushq %rbp.cfi_def_cfa_offset 16.cfi_offset %rbp, -16movq %rsp, %rbp.cfi_def_cfa_register %rbpsubq $16, %rspmovl $0, -4(%rbp)leaq L_.str(%rip), %rdimovb $0, %alcallq _printfxorl %eax, %eaxaddq $16, %rsppopq %rbpretq.cfi_endproc ## 結束函數.section __TEXT,__cstring,cstring_literals L_.str: ## @.str.asciz "hello world!\n".subsections_via_symbols匯編成可執行文件
在 Windows 中,現在主流的可執行文件的格式是 PE(Portable Executable File Format),而其中的“Executable”縮寫就是很多人熟知的 EXE。在 macOS 中,可執行文件被稱為Mach-O executable file。
如果使用file命令來查看一個可執行文件的話就可以看到,這里我們查看 Xcode:
所以最終目標是要把hello.s這個匯編文件,“變”成一個Mach-O executable file。
這里有兩種方法:
方法 1
由于這個程序十分簡單,也沒有鏈接特殊的庫,可以直接使用以下命令來:
$ gcc -nostartfiles helloworld.s $ chmod 755 a.out $ file a.out a.out: Mach-O 64-bit executable x86_64這時候可以看到,a.out便是需要的Mach-O executable file。
運行一下看看:
非常不錯。
方法 2
這種方法是常規做法,首先使用as來匯編代碼,并且修改權限:
$ as hello.s $ chmod 755 a.out這里需要注意一點,as生成的是 Mach-O 對象文件(Mach-O object file),而不是Mach-O executable file,是不能直接運行的,如果直接運行會提示cannot execute binary file。在 Windows 中,對象文件被稱為 COFF(Common Object File Format)。
這時候需要使用連接器ld來處理對象文件。但是,如果簡單的使用ld 會出現以下情況:
$ ld a.out Undefined symbols for architecture x86_64:"_printf", referenced from:_main in a.out ld: symbol(s) not found for architecture x86_64這是因為使用了 C 標準庫的_printf,但是ld默認搜不到。所以加上庫地址就可以,如下:
$ ld a.out -o hello -lSystem -L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib特別注意!一般Mach-O executable file是不加任何后綴的。
這時候得到的hello便是需要的Mach-O executable file。使用file命令來檢查一下:
然后運行一下看看:
$ ./hello hello world!運行完美~
結尾
本文還會時不時更新一下,修改一些問題,添加一些內容。
總之,希望能幫到有需要的人~
總結
以上是生活随笔為你收集整理的macOS 汇编指南的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 动画图解:十大经典排序算法动画与解析,看
- 下一篇: 13种常用按钮、文本框、表单等CSS样式