談談.git 目錄
如果有使用git的朋友,可能會知道git是一個分散式版本控制系統。這表示repository會放一份在本機上面。仔細或是有看書的人,會知道這些repository沒有意外會放在工作目錄的.git
下面。今天無聊來這個目錄戳戳看。
因為愈寫愈多,還是弄一下目錄好了
測試環境
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
.git目錄列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
背景知識
這邊只列出需要的背景知識,可能有錯。
- Git 的基本上資料有分blob, tree, commit, tag這四種型態
- Git 的branch可以視為放一個檔案,這個檔案存放某個commit的HASH資訊
多說無益,直接操作,先來看這四種型態是三小
1 2 3 |
|
來看一下 fd5d6abe34f41f8687c1fc5e2ab0a2f65c570304裏面是啥
1 2 3 4 |
|
可以看到有放
- tree型態的HASH
- 上一個commit的HASH
- commit的訊息
接下來來看tree吧
1 2 3 4 5 |
|
有沒有和Linux的File system很像?目錄tree資料放的是inodeHASH值和檔案名稱的對應表。
我們可以看到HASH的型態有tree和blob,理所當然來看看blob吧。
1 2 3 4 5 6 7 |
|
很明顯這是一個資料存放的地方。
然後我們來看branch是不是真的放在檔案,檔案內容是某個commit HASH吧,直接看範例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
.git第一層檔案
用file看一下,可以看到大部分都是純文字檔:
1 2 3 4 5 6 7 |
|
接下來分別討論
index
先看下面的操作。
1 2 3 4 5 6 7 8 |
|
有興趣的人可以把| wc -l
去掉玩看看,基本上這個是在描述repository的目錄結構。也就是說,哪個檔案要放在那個目錄。更精確的來說,協助那個blob hash要放在哪個tree中。根據這邊的說法,這個檔案可以協助
- 提供產生tree object時需要的資料
- 提供比對working directory和tree的資訊
- merge產生衝突時,可以從index取得的資料協助解決衝突。不過這邊不是很懂,就單純字面翻譯了。
packed-refs
簡單來說,考量效率,git提供pack ref目錄的功能,ref的概念請看前面背景知識。
一樣,看例子比較快。
先用git show-ref
看看我們有哪些reference
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
看看packed-refs
裏面是三小?有沒有發現和上面很像啊?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
看一下ref目錄,上面的那些reference並不存在在.git/ref
裏面
1 2 3 4 5 6 7 8 9 10 |
|
好,生一個branch看看。
1 2 |
|
喔喔!.git/refs
出現了剛才產生的ref
1 2 3 4 5 6 7 8 9 10 11 |
|
跑一下git gc
整理一下
1 2 3 4 5 6 |
|
疑?剛才的branch不見了。
1 2 3 4 5 6 7 8 9 |
|
跑去pack-ref了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
config
其實這個是個大哉問,就值得專門開一個章節討論。所以我整理到這個頁面,請自行前往閱讀。
ORIG_HEAD
這個檔案很有趣,一開始其實不存在。後來不知道怎麼突然跑出來,問了估狗和男人(man git reset)後得到的答案就是當reset的時候會把舊的HEAD hash放到這邊。為什麼要這樣做呢,當然是反悔用的。你可以man git commit
找ORIG_HEAD
就可以看看git commit --amend
同效果的範例了。
description
懶得解釋,跳過
HEAD
望文生義,當然是指向目前所在的commit。
等等!
指向目前所在的commit是三小? 一樣,來看例子。
目前clone下來,裏面放的是一個檔案,檔案裏面是什麼呢?一樣是個commit HASH
1 2 3 4 5 6 7 8 |
|
那我直接checkout一個不是branch的可以嘛?當然沒問題。 可以看到git會把你checkout的commit HASH寫入.git/HEAD
1 2 3 4 5 6 7 8 9 10 11 12 |
|
第一層目錄
branches
快過期的東西(出處),跳過。
hooks
hook,這個翻成中文很鳥,保留原文。基本上就是一組callback,特定的時候會去呼叫。我目前生意沒有做很大,有需要再去看。列出預設的檔案如下
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
info
儲存資訊,廢話。目前裏面只有一個exclude,而且檔案內容還都是註解。但是這邊有說還有其他檔案。另外值得提的是exclude說明有提到.gitignore
針對的是git status
, git rm
, git add
, git clean
。其他的操作還是得在.git/log/exclude
中設定。
logs
這是存放log的地方。log是什麼呢?直接看個例子。
我們先新增一個測試檔案
1 2 3 4 5 6 |
|
執行git reflog
,可以看到你剛才的動作以及有當次HEAD的commit HASH已經被記起來。
1 2 3 4 5 |
|
這東西有什麼用處呢?當然是讓你反悔用的。再來看個例子
首先開一個branch
1 2 |
|
新增並commit file1
1 2 3 4 5 6 |
|
然後新增並commit file2
1 2 3 4 5 6 |
|
切回master並且宰掉剛才的branch
1 2 3 4 5 6 |
|
假設上一個動作是手滑誤刪,能不能反悔。 YES YOU CAN!
先看看log
1 2 3 4 5 |
|
可以知道上次branch最後commit的HASH,那麼我們就可以切過去然後開另外一個branch了。
1 2 |
|
可以看到資料回來了。
1 2 3 4 5 |
|
當然這還是險招,git本身保留是有保存期限的。有興趣問男人。man git gc
不知道有沒有會問:「啊不是要介紹.git/logs
嘛?」
問得好!猜猜剛才git reflogs檔案從哪裡讀出來?
一樣請出strace大大
1 2 3 4 |
|
有看到.git/logs/HEAD
吧?有沒有想看一下裏面是啥?至少我想看。
1 2 3 4 5 6 7 |
|
精確的來說,.git/logs
下面不只紀錄HEAD的log,還有各種ref的log。有興趣的朋友可以自行參考這邊,並且進去目錄逛逛。
objects
先看剛clone下來的目錄結構
1 2 3 4 5 6 |
|
來生一個目錄和並且commit一個東西進去。
1 2 3 4 5 6 7 |
|
然後看看這個目錄變化吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
接下來把目錄和檔案混起來,用git cat-file -p
看看裏面是啥
1 2 3 4 5 6 7 |
|
1 2 |
|
1 2 3 4 |
|
1 2 |
|
其實不難猜,你local commit的東西會被處理後變成object,並且依照hash分門別類地存放。
接下來我們來做個測試
1 2 3 4 5 6 |
|
可以看到,剛才的目錄全部消失,而pack目錄的檔案名稱也和前面的不同了。對照上面git gc
的訊息,可以知道git gc
做了壓縮,並且將這些object一起壓到pack目錄的檔案中了。
1 2 3 4 5 6 7 8 9 |
|
所以我們可以從觀察中做出結論。Git object的存放有兩種型式
- loose object:就是剛才看到用[HASH前兩碼]/[剩下HASH] 的目錄檔案結構
- packed object: 把object壓縮成兩個檔案
而looose object型式經過git gc
後會有可能轉換成packed object,反之亦然。詳細規則問男人。
由於git gc
是用來清除和整理local repository,也就是說做了git gc
是有可能刪除用不到的資料。詳細情況一樣請問男人man git gc
refs
- 背景知識和packed-ref有提到,就不要拖台錢了。
參考資料
- Stackoverflow: What does the git index contain EXACTLY?
- Git Community Book: The Git Index
- Stackoverflow: HEAD and ORIG_HEAD in Git
- ProGit: 10.2 Git Internals - Git Objects
- what’s inside your .git directory
- git-pack-refs - Pack heads and tags for efficient repository access
- ProGit: 8.1 Customizing Git - Git Configuration
- gitrepository-layout - Git Repository Layout
- Git Community Book: How Git Stores Objects
ProGit: Customizing Git - Git Configuration導讀
目錄
測試環境
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
簡易使用方式
最簡單的使用方式
- 新增/更改選項
- git config 型態 名稱 你要設定的值
- 常見的型態有
--system
或是--global
- 常見的型態有
- git config 型態 名稱 你要設定的值
- 讀取選項
- git config –get 名稱
值得注意的是,git config 的名稱一般來說會使用.
作為分類的參考如
git config test.user.name.first Liao
git config test.user.name.last Wen
而在設定檔中,會用[]
把第一個.
的前面的字串放在前面,然後最後一個.
後面的字串和你要設定的值變成
* 最後一個.後面的字串=你要設定的值
你應該要問,那中間的呢?好問題,中間的就放在[]
裏面囉。
很模糊?看例子比較快。
1 2 3 4 5 6 7 |
|
git config參考檔案以及順序
要注意的是/etc/gitconfig不一定存在,我的是沒有。所以生一個測試驗證用。
/etc/gitconfig
- 由
git config --system
產生
- 由
~/.gitconfig
- 由
git config --global
產生
- 由
你的local repostiory/.git/config
- 在
你的local repostiory
下面執行git config
產生
- 在
檔案讀取順序是由上往下,全部都有資料的話。最後回傳值順序是由下而上。 要練習驗證,所以來看一下。
用strace看git config --get user.name
開檔案的順序。
1 2 3 4 5 6 7 8 |
|
可以看到/etc/gitcnfig
沒有user.name
1
|
|
~/.gitconfig
下有Wen.Liao的字串
1 2 3 4 |
|
同樣的,目前repository下面的config是沒有user.name資料
1
|
|
接下來改一下user.name
1 2 3 4 5 6 7 |
|
可以看到目前目錄下.git/config
新增了user.name
1 2 3 4 |
|
驗證是否.git/config
的值真的會比~/.gitconfig
優先
1 2 |
|
git config 選項節錄
Git config 選項有分為server端和client端,大部分選項和client有關,文件中節錄部份,我再節錄我有興趣的部份。想要知道全部的選項可以問男人。man git config
。再次提醒,如果是你要套用到全部git repository請用git config --global
,不然這些選項只會在你目前git repository生效。
core.editor
- 你要commit 時候會用的編輯器
commit.template
- 這個比較重要,如果你要套用commit template,就用這個。把你自己或是團隊的commit template引入吧。我自己會用# 為template加入註解。
color.ui
- 為你的UI文字上色。可以設成
true
或是false
- 為你的UI文字上色。可以設成
指定使用外部比較命令
git可以指令使用外部比較命令,首先要搞清楚git 會送什麼參數給外部命令,所以我們先寫個script印出參數,並且指定外部diff的時候使用這個script。
1 2 3 4 5 6 7 8 |
|
這些參數的順序是
1 更動的檔案名稱 2 將被更動前的檔案內容另存新檔路徑 3 被更動前的檔案blob hash 4 被更動前檔案權限 5 將被更動後的檔案內容另存新檔路徑 6 被更動後的檔案blob hash 7 被更動後檔案權限
對我們來說,有興趣的是2和5,所以我們可以將命令更動為
1 2 3 4 |
|
meld是一個GUI程式的比對工具。接下來就來測試吧
1 2 3 4 |
|
GUI畫面如下:
手冊上面還有提到merge tools 的設定,本人不感興趣。跳過。
參考資料
談談git Remote
在軟體專案開發常常會需要比對不同的repository。舉例來說,你可能在遠端有一套軟體專案,這個專案是從upstream fork 下來,那麼如果要把upstream 新的功能合併到專案,人肉合併往往是最容易出錯又最沒效率的方式。如果這兩個專案都有git,那麼git remote就是你的救星。針對剛才講的更詳細的use case可以看Git Hub的範例
直接拿Use case範例,不囉唆。 Demo情境
- 有兩個遠端repositories: repo1, repo2
- 將repo1 clone下來到local repository,另外一個透過git remote加入到local repository
- 在local建立一個branch,對應到repo2
- merge repo1到repo2
- 要注意的是其實以upstream 情況是剛好相反,一般來說repo1,也就是你clone的才是你要開發的專案。選擇這樣的case單純只是吃飽撐著。
詳細行為範例如下
建立測試環境
產生兩個遠端repositories: repo1, repo2
repo1
1 2 3 4 5 6 7 8 9 10 |
|
repo2
1 2 3 4 5 6 7 8 9 10 11 |
|
看一下目錄架構
1 2 3 4 5 6 |
|
新增remote URL
就 git clone,沒啥好說
1 2 3 4 5 6 7 |
|
建立對應remote URL的local branch
我們用了git remote add 本地如何稱呼remote remote的URL
1 2 3 4 5 6 |
|
接下來把remote URL的repository 拉下來
1 2 3 4 5 6 7 |
|
然後建立一個branch,對應到repo2的master
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
在local合併兩個Romote Branch
剩下非常直覺,就把兩個local branch merge,整理完衝突收工。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
請注意這個case不能夠把更動push 回repo2/master 會噴錯誤如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
簡單翻譯一下,目前local branch名稱在repo2上面沒有,你要嘛
- 指定push到repo2的master:
git push repo2 HEAD:master
- 要嘛指定push local branch到repo2 repository上
第一個情況需要bared repository,時間關係有空再談。
參考資料
島唄 - the Boom
這是一首反省二戰日本政府在沖繩島的決策造成大量當地人冤死悲劇的歌曲。
在二次大戰末期,米軍開始準備入侵日本本島,因此需要佔領沖繩作為前進基地。當時的日本政府在當地強徵年輕男女學生在戰場上做雜務以及醫療協助。同時大力宣傳米軍的邪惡形象,宣稱米軍殘暴邪惡,表示與其被米軍俘虜生不如死,不如自殺比較痛快。網路上可以看到日本政府會發手榴彈給當地居民的資料。加上日本政府強力徵收糧食,估計戰役結束後平民死亡人數預估超過十萬人(出處)。
回到主題,這首歌是1992年出版的。根據Wikipedia的說明,主唱者去沖繩的時候,參觀了姬百合和平祈念資料館,了解這片土地上發生的事情,以及館內倖存者親口說出的故事後,感到非常惆悵。當他離開姬百合和平祈念資料館的時候,映入眼前的是一整片的甘蔗田,讓他動起創作的想法。這就是The boom出版島唄(shima-uta)這首歌的由來。
我不會日文,不過ptt有中文歌詞翻譯的歌詞,也有詳細的背景說明。希望人類記取這些慘痛的教訓,不要再放任不負責任的政府亂搞,最後導致悲劇發生。
參考資料
Ubuntu 14.04 下面的VirtualBox存取USB設備
照慣例,列一下測試環境
- Host OS
1 2 3 4 5 6 |
|
Guest OS 同上。
VirtualBox 版本: Oracle VM VirtualBox Manager 4.3.22
主要有兩件事要做,就是
將使用者加入Virtual Box 群組
把使用者加入vboxusers
群組
1
|
|
Double check是否已經在vboxusers
group 指令
1
|
|
安裝延伸套件(Optional)
去VirtualBox官方網站下載Oracle VM VirtualBox Extension Pack。
安裝
1
|
|
- 從主選單中要使用USB VM的Settings->USB選單中,勾選
Enable USB 2.0 (EHCI) Controller
,請確認VM是Powered off狀態。 - 驗證:
- Start VM
- VM視窗中選Devices -> USB -> 挑你想要使用的USB
- Guest OS開完機,Linux的話用可以使用lsusb驗證
參考資料
系統函式庫的debug 資訊放在那邊?
在查詢hello world中的_start
呼叫__libc_start_main
部份,使用到了反組譯工具。觀察反組譯的部份發現有可能需要看一下libc本身的__libc_start_main
組合語言的行為。以前的經驗,這種情況先拉有debug 資訊的套件來看,所以拉了libc6-dbg下來,結果下來的結果,完全無法反組譯。後來請教網友Scott Tasi才發現我錯很大。
先講結論:
- libc的debug 資訊和本身的binary完全隔開。所以反組譯要看的仍然是在原本的libc.so這個檔案。
年紀大了才發現能夠從結論中問問題收穫會更多,所以我就來問
- 問題一:誰來用這些debug 資訊?
- 問題二:既然debug 資訊不在binary內?那麼怎麼找到額外的debug 資訊?
先來回答誰來用這些debug 資訊?其實這個根本就是廢話,gdb用心酸的啊。其實這只是在鋪梗,這表示找第二個問題的答案就會和gdb有很大的關係,也就是說我們可以把問題縮小到和gdb相關 (註一)。
好,我們來重複問題二
- 既然debug 資訊不在binary內?那麼怎麼找到額外的debug 資訊?
從常理來猜測,顯然是原本的binary有地方告訴gdb「有額外的除錯檔案,請你載入的時候去那邊抓除錯資訊」。我們直接看GDB手冊怎麼說
- gdb允許把debug 資訊放在binary外面,而gdb可以透過兩種方式取得
- 執行的binary內提供link讓gdb可以摸到有debug 資訊的檔案。如果是執行檔,可能就稱為
執行檔.debug
。- 這個link資料,放兩個東西
- 不包含directory的檔案名稱
- 該檔案名稱算出的CRC 碼
- 這個link資料,放兩個東西
- 透過build ID,因為和我找的無關,跳過。我們focus在第一個方式。
- 執行的binary內提供link讓gdb可以摸到有debug 資訊的檔案。如果是執行檔,可能就稱為
有了debug link資訊後,仍然有幾個細節需要釐清
- 問題三:debug 資訊檔案放在哪個目錄?
- 問題四:debug link放在binary 的哪裡?
一樣來看手冊。手冊上說debug 資訊檔案會依以下的順序搜尋
- 該執行檔的存放目錄
- 該執行檔的存放目錄下面同樣目錄名稱,但是加上.debug。如/usr/bin -> /usr/bin.debug/
- 系統預設的debug 目錄
以上是問題三的的解答,剩下問題四我就認為可以把整個故事說完。所以來看問題四吧。
- 問題四:debug link放在binary 的哪裡?
同樣的在手冊中有提到,binary 中有特別的section稱為.gnu_debuglink
,就是存放debug 資訊檔案的資訊。存放的資訊為
- 存放debug 資訊的檔案名稱
- padding for 4-byte alignment
- 4 byte CRC checksum
好啦,有了完整的故事,當然要看是不是在唬爛。我們來看libc.so吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
那麼這個和我原本要反組譯libc的結果有什麼關係?嘛,旅行的精華就是在迷路不是嗎?
測試環境
1 2 3 4 5 6 7 8 9 10 11 12 |
|
參考資料
- GDB Manuel: Debugging Information in Separate Files
- fcamel: gdb 如何找到 debug symbol
- .gnu_debuglink or Debugging system libraries with source code
註解
Gcc的幾個參數筆記
ssh登入遠端主機自動設定X Display 變數
前言
因為用X用習慣了,常常會連線到另外遠端電腦,然後透過X把該台電腦軟體畫面輸出到本機。這時候的標準流程會是
- ssh登入到遠端
- export DISPLAY=你的本機IP:0.0
每次都要打這些,還要查自己本機IP很煩。所以整理了兩光的script提供以後剪下貼上。
另外有人會問為什麼不直接用ssh -X
連過去?原因是因為我習慣設完display後,開一個遠端終端機丟在背景然後登出目前的ssh session,這樣的操作在ssh -X
下從來沒有成功過。我了遠端終端機後就算放在背景,一樣目前終端機會卡住。如果暴力把目前終端機關掉,那麼所有X的session都GG。實在懶得找原因,反正這是個workaround的世界(煙)。
背景說明
上面操作中,本機需要設定
- X allow TCP
- xhost 加入允許連進來的IP
這兩個部份請自行估狗。
另外本機和遠端主機用相同的Distribution資訊如下,測試端的遠端主機是一台沒有GUI的Ubuntu server。
1 2 3 4 5 6 |
|
使用方式
把下面的描述放在~/.profile
最後面,下次ssh登入後就可以直接開啟X應用程式把畫面丟回本機了。
1 2 3 4 5 6 7 8 9 |
|
Linux中誰來呼叫C語言中的main?
記得很久以前聽說在Linux執行檔案時,真正的起始點並不是main,加上之前有看到單純ld會幫你偷偷link一些沒看過的object檔案,所以這次就來看到底真相為何?
測試環境
因為很假掰想要順便接觸一下ARM的組語,所以這次測試就使用Qemu跑ARM的Debian。
1 2 3 4 5 6 7 8 9 |
|
測試原始碼,一樣是大家熟悉的Hellow world
1 2 3 4 5 6 7 8 |
|
不知道各位還記得前面有提過,執行檔中有.text
的section。要執行的機械碼會放在這邊。我們先來看看hello1執行檔會從那邊開始?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
從readelf可以看到起始點為0x102f0,那麼0x102f0是在那邊呢?我們再去看symbol table可以看到很巧的就是.text
的起始點。
1 2 3 4 5 6 7 8 |
|
好了,那麼.text
這邊起始的程式是什麼?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
很有趣,沒看到main()
,反而看到_start
。到底是_start
是什麼呢?還記得Linker script嗎?裏面有一個ENTRY
指令,可以指定程式從那邊開始跑,先來看一下預設的ENTRY
是不是也是_start
?
1 2 |
|
目前我們只知道執行檔起始點是_start
,而不是main
,那顯然有人幫你把執行檔加碼,以至於你的執行檔出現了_start
。最偷懶的方式就是去找binary看看是不是有這樣的symbol。
1 2 3 4 5 6 7 |
|
OK,的確有object檔案裡面有_start
,我們再來確認編譯的時候會不會link這些檔案。
1 2 3 4 5 6 7 8 9 10 |
|
而_start
會呼叫外部函數__libc_start_main
,我們透過LD_DEBUG
來看一下。
1 2 3 4 |
|
可以看到,在./hello1中有去找__libc_start_main
,最後去libc.so.6
找,並且找出libc.so.6
中__libc_start_main
的位址(即binding)。而__libc_start_main
的prototype如下
1
|
|
看到有趣的東西嘛?我有看到
- main函數當作function pointer傳入
- main函數的參數
- 其他不知道三小的function pointer
- init
- fini
- rtld_fini
從這邊我可以猜測這個函數就是呼叫一堆callback function,這些callback function就是上面列的死人骨頭。
從手冊的說明可以看到__libc_start_main()
是用來執行環境的初始化、呼叫main
函數並且傳遞參數,當main
函數結束後處理回傳值。手冊提到的範例詳細行為有
- 檢查權限,確保安全性
- thread subsystem初始化 (我可不知道什麼thread subsystem唷)
- 向
rtld_fini
註冊release callback function,當shared object結束時使用該callback釋放資源 - 呼叫init callback function
- 呼叫main callback function並且帶入參數
- 當main callback function結束後,將回傳值作為參數呼叫exit
我們再回頭看看_start
的組合語言:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
有趣的地方是這3個位址
1 2 3 |
|
從這邊可以看到這3個位址分別是
- 10320: 000104b4 .word 0x000104b4
__libc_csu_fini
- 10324: 00010420 .word 0x00010420
main
- 10328: 00010448 .word 0x00010448
__libc_csu_init
也就是說,main
和__libc_csu_init
分別當作第一和第四參數傳給__libc_start_main
,而__libc_csu_fini
則被丟到stack,一樣傳給__libc_start_main
了。
結論
Linux執行程式的起始點並不是main
,而是glibc binary中crt1.o
準備的_start
。這個start主要將你的main
,還有一些hook函數丟給__libc_start_main
,接下來libc的__libc_start_main
樵好事情後才真正執行你的main
,並且還要在main
結束後清理戰場。
延伸閱讀
- Hook function
參考資料
- Linux Standard Base Core Specification 4.0: __libc_start_main
- 不知道是不是過期,請小心服用
- Computer Science from the Bottom Up: Chapter 8. Behind the process (大推!)
- Mini FAQ about the misc libc/gcc crt files
- allenlsy: C Essense (2) - C and Assembly
- 全系列都推!
完整反組譯程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
|