常用功能的 plugin 及快捷鍵:

  • 游標停在字上的時候會自動 highlight 同樣的字
    開啟 vim 後輸入 z/,目前還沒找到怎麼一開 vim 就啟動自動 highlight。
  • 跳到游標所在 variable 或 function 的宣告
  • 在 .cpp 跟 .h 之間切換
    a.vim (:A)
  • 跳到游標所在的 function 的定義
    cscope (ctrl+\ g)
    ctags (g] or ctrl+])
  • 跳到游標所在的 variable local 宣告
    ctags (gd)
  • 跳到游標所在的 variable global 宣告
    ctags (gD)
  • 全 project search
    cscope (ctrl+\ t)
  • 列出 file 中有哪些 function
    taglist (F8)
  • 自動補齊
    於 insert mode ctrl + n
  • 自動補括號
  • hex mode
    :%! xxd
  • 切換 history
    ctrl + i & ctrl + o
  • 多行註解
    ESCctrl + V 選範圍、大寫 I、輸入註解符號、ESC
  • 多行取消註解
    ESCctrl + V 選範圍、delete

My .vimrchttps://github.com/cjwind/dotfiles/blob/master/vimrc

ctags taglist

$ sudo apt-get install ctags

切到 project 資料夾產生 tag 資訊:

$ ctags --extra=+f -R *

加上 --extra=+f 可以在 vim 中使用 :tag <filename> 跳到該檔案,:tag <filename> 後再 ctrl + t 可回原本檔案。

http://www.vim.org/scripts/script.php?script_id=273taglist_45.zip,解開後將 taglist.vim 放到 ~/vim/plugin

~/.vimrc 加入相關設定:

1
2
3
4
5
6
let Tlist_Ctags_Cmd = '/usr/bin/ctags'
let Tlist_Auto_Open = 1 " 讓 Tlist 自動開啟
let Tlist_Show_One_File = 1 " 不同時顯示多個文件的tag,只顯示當前文件的
let Tlist_Exit_OnlyWindow = 1 " 如果taglist窗口是最後一個窗口,則退出vim
let Tlist_Use_Right_Window = 1 " 在右側窗口中顯示taglist窗口
nnoremap <silent> <F8> :TlistToggle<CR> " F8 為開啟/關閉 Tlist 的快速鍵

ctrl + w 再加方向鍵可以切換 window,例如加右鍵就是跳到右邊的 window。

patch

有時候切換 tab 會出現 error Taglist error: Error detected while processing function <SNR>29_Tlist_Refresh_Folds,可用 patch 解決:$ patch -p0 ~/.vim/plugin/taglist.vim taglist.diff

cscope

$ sudo apt-get install cscope

切到 project 的資料夾產生 cscope 資料庫:

$ cscope -RC

之後用 vim 開啟 source code,可用 :cs 指令使用 cscope 的功能。也可以在 ~/.vim/plugin 中放 cscope_map.vim 加快捷鍵:

1
2
3
4
5
6
7
ctrl+\ s "s表Symbol,列出所有參考到游標所在字串的地方,包含定義和呼叫。
ctrl+\ g "Find this definition
ctrl+\ c "c表Call,列出所有以游標所在字串當函數名的地方。
ctrl+\ t "t表Text,列出專案中所有出現游標所在字串的地方。
ctrl+\ f "f表File,以游標所在字串當檔名,開啟之。
ctrl+\ i "i表Include,以游標所在字串當檔名,列出所有include此檔的檔案。
ctrl+\ d "d表calleD,以游標所在字串當函式名,列出所有此函式呼叫的函式。

自動 highlight

.vim/plugin 加入 autohighlight.vim

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
" Highlight all instances of word under cursor, when idle.
" Useful when studying strange source code.
" Type z/ to toggle highlighting on/off.
nnoremap z/ :if AutoHighlightToggle()<Bar>set hls<Bar>endif<CR>
function! AutoHighlightToggle()
let @/ = ''
if exists('#auto_highlight')
au! auto_highlight
augroup! auto_highlight
setl updatetime=4000
echo 'Highlight current word: off'
return 0
else
augroup auto_highlight
au!
au CursorHold * let @/ = '\V\<'.escape(expand('<cword>'), '\').'\>'
augroup end
setl updatetime=500
echo 'Highlight current word: ON'
return 1
endif
endfunction

輸入 z/ 可開關自動 highlight 的功能。

reference here

a.vim

在 header 及 source 之間切換。script

切換指令為 :A

自動補括號

Auto Pairs

將 script 放到 ~/.vim/plugin/ 底下。

Ref

大學時因為很任性的理由沒有修軟體工程,所以 agile 是一直到開始工作才聽到。之前是聽過 XP 跟 pair programming,不過沒有很清楚在幹嘛。話說 pair programming 實在要看狀況用,像我這種基本上屬於內向害羞的類型,用 pair programming 大多數狀況下根本直接腦殘化…= =

之前被拐去上 scrum 的課,說不定是因為講師一直強調 agile 本身精神很重要云云,有個想法一直在腦袋徘徊不去(?),只好來 murmur 一下看能不能清爽些。阿不過這篇只講對 agile 精神的想法,scrum 方法我不會(欸)。

我將 agile 精神類比為適應,因為根本上概念是共通的。適應就是因應改變,無論那改變來自外在環境抑或是自身變化。差別只在於生物上各種生物有不同的適應方式,人對於環境以及種種變化所做出的調整也是適應,而 agile 則是將這樣的想法套用於組織性的軟體開發。

需求改變(外在環境)、內部人員的不同(內在改變)等等都是變化,有了基本精神後當然是以各種工具與方法達成。而現在有許多經過不少人血淚斑斑的試驗過、覺得還不錯的方法可以使用,但是最後依然要找出適合組織與情境的方式。

我是從個人的角度出發去看「因應變化」這件事。因應變化常常帶著不確定性,所以有時候不太討喜,但是近年我喜歡這種會因應變化的觀念,因為這代表彈性、可能性以及選擇。我喜歡用「成長」的角度去看待改變,改變不見得是成長,但是沒有改變幾乎難以有所成長。有改變代表有新東西,有新東西代表有新選項,有新選項代表有不同未來的可能性。倘若不滿意現況,如果希冀有所不同,又怎麼能夠期望同樣的方式能帶來不同的結果?

至於結果是更好還是更壞,如果以從個人角度出發來看,我是不太在意。因為覺得不好,再改就是了,這不正是彈性的好處?我傾向相信,終究會慢慢摸索出適合的方式。而那方式,也可能只適用於某一陣子,那只是一個暫時的答案,不是絕對。

定義物件間一對多的關係,當一個物件改變狀態,其他相依者都會收到通知並自動被更新。

適用場合

某個物件擁有某些 state,還有一堆其他物件很在乎這些 state 有沒有改變,這些物件在 state 改變時需要做些事情。這邊的 state 是抽象概念,舉凡一個 button 被 click、load data 的 progress、load data 完成與否、畫面是否被修改等等都可以看作 state。另外,一個 object 可能會有很多種 state。

網路上很喜歡用的說法:observer 是一種訂報紙的概念。簡言之,有間報社(subject or observable),要訂報紙的人(observer)跟報社說他要訂報紙,之後報社有新報紙了(狀態改變)就會通知這些訂戶,訂戶拿到報紙後或許拿來看、或許拿來墊便當(?),想幹嘛就幹嘛。如果一個訂戶不想收到新報紙了,就跟報社說一聲退出訂閱,之後報社就不會再通知他了。

再舉另一個例子:UI 操作上滑鼠點了某個東西,程式其他部分需要因應點選做些事情時也適用 observer pattern。

UML

Observer Pattern

Observable 中會有些 state,state 變化時 call NotifyXXX() 通知 observer 們 update。一種做法是 NotifyXXX() call observer 的 update(),而 obsever 會在各自的 update() 中 implement observable 狀態改變時要做的事。

observer 如何取得 observable 的資料?

observer 拿 observable 的資料有兩種方式:

  • push:由 observable 在通知時一起傳給 observer。
  • pull:observer 用 observable 提供的 getter 取得資料。

我是還感覺不出來兩種方式的好壞啦……

有的沒的

  • observer 在 update 時不可以依賴被 notify 的順序,因為不同的 observable 實作可能導致結果不同。
  • Java 裡有現成的 observer pattern API。
  • Java 的 ActionListener 機制是種 observer pattern 的實作──當某件事發生時會 call ActionListener 相應的 function。

Qt signal-slot 轉成 native 寫法

Qt 的 signal-slot 在用途是特定的狀況下,例如某些 signal-slot 是特別針對某個操作時,可以改成自己實作 observer 並取代之。什麼時候會這麼做?不想用 Qt 做某些 notify 甚至不想用 Qt 的時候…

我覺得 observer 跟 listener 差不太多,這裡說的 listener 是稍微簡化的 observer,不會有如上述的 observable interface,而是 listenable 的 class 各自自行增加 listener 相關 member 及 function。

如何將 Qt 的 signal-slot 改成 native 的 listener 寫法、自己處理 notify 呢?

  1. 看懂原本 notify 的流程,區分誰是 listener 誰是 listenable。一般來說 signal 的 sender 是 listenable,signal 的 receiver 是 listener。確認要改哪些 signal、slot、connect()、disconnect()。
  2. 在 listenable class 增加 listener list、add 跟 remove listener function。
  3. 在 listener interface 增加 update function,也就是當某件事發生時會被 call 的 function。
  4. 修改 listenable class 的 emit signal,改為 call listener 的 update function 或 NotifyXXX(),由 NotifyXXX() 再 call listener 的 update function。如果有多處需要通知 listener,建議寫成 NotifyXXX()。如果只有一個地方需要通知,也可以不用 NotifyXXX()。
  5. listener class 繼承 listener interface 並 implement update function。將原本的 slot 改為一般 function,接著看要由 update function call 還是直接 rename 為 update function。如果原本是 auto 或 queued connection 要注意 thread issue。
  6. 修改 listener class,將 connect() 及 disconnect() 改為 call add 及 remove observer。
  7. 需注意 listener 及 listenable object 的生命週期,如果 listenable 活得比 listener 久,listener 死之前要將自己從 listenable 的 listener list 中移除。

Qt 的 signal connection 有些特殊功能也要一併處理:

  • queued connection 可能隱含換 thread,需釐清原本程式是否意圖使用換 thread 機制。
    如果有換 thread 就不是單純 observer pattern 可以處理的,可能要改用 thread + event loop,或 listener 的部分可以使用 Qt 則在 listener 以 signal-slot 換 thread。
  • direct connection 幾乎等同直接 call function,不需要額外處理。
  • unique connection 代換作法之一是在 register observer 時做 filter,已經是 observer 的 object 就不再加入 observer list。

Ref

今天看到這篇文章,加上近日對於整理筆記之厭倦,在想到底寫筆記是寫來幹嘛的?

那篇文章表示不用寫「資訊」,但以學習知識來說,我還是需要一點「重點整理」方便日後查找,尤其是一些從書上看來、稍微消化過但也還沒熟到整個記下來的部分。資訊的確幾乎都可以找 google 大神,但是重新 google 到的資訊可能跟我的印象有出入,還有一些眉眉角角不見得記得,有個地方作為資訊的集中地對我還是有用的。

只不過,有時候似乎會趨向小時候在課堂上抄寫筆記的狀況,像在抄書。這感覺就怪怪的,有時候分不清楚自己是在抄書還是那真是重點(好吧,我猜如果覺得很厭倦的話大概就是在抄書或者已經不需要寫了)。想著想著發現原來今年初寫過筆記這回事

以上是跟專業、學習知識有關的「筆記」。至於看其他書啊、聽演講啊之類的,我比較會寫心得感想,像那篇文章所說的第二種筆記。在專業有關的學習上,這種感想會在書裡變眉批,這裡一句、那裡一段的,有時候是疑問,有時候是吐槽(欸?),但這種亂七八糟的心得就不太會去整理了。

可能會慢慢增加對於專業領域的想法吧,我對時事或一些事情會有某些想法,但很奇怪,對於自身專業卻不太有自己的想法。

C++ 不像 Java 有 interface,這邊說的 interface 是所有 function 皆為 pure virtual function 的 abstract class。

interface 依然要有 virtual destructor,否則用 interface pointer 去砍 object 的時候會變成 undefined behavior。如果希望 interface 中的 virtual destructor 仍是 pure virtual,可以這樣寫:

1
2
3
4
5
6
7
class Interface
{
public:
virtual ~Interface() = 0;
};

inline Interface::~Interface() { }

由於只要有 class 繼承 Interface,Interface 的 destructor 就會被 derived class call 到,所以必須要有 definition 才不會 link error。

virtual destructor 另一個使用場合──希望訂一個 interface 但不想訂定其中要有什麼 function──不想訂 function 但又需要該 class 是 abstract class 時就可用 virtual destructor 達到目的。聽起來有點怪,我遇到這種狀況是希望有個 interface 可以代表某種類的 object,但是在 interface 的階段卻又無法確定 derived class 會有那些 function,最後因為覺得結構上不需要而沒有真的使用,不曉得有沒有其他更好的方法?

2018-12:現在看看覺得「希望訂一個 interface 但不想訂定其中要有什麼 function」的情況有點怪……又想不起來之前遇到什麼了……要訂 interface 至少要有基本 function,否則是否先不訂 interface、先做 class,等漸漸看到有共通的 function 時再訂定 interface?

Ref

看完《深入淺出物件導向分析與設計》的筆記,這篇概括整理用 OOAD 開發軟體的開發週期,沒有太多細節。

1. 搞清楚客戶想要什麼

跟客戶聊天,從模模糊糊中搞清楚他想要什麼。或者問可以決定要做什麼的人,不管那個人是 PM、PL 還是其他各種頭銜…

利用 Commonality 及 Variability 了解客戶想要什麼、軟體要做什麼。

老實講,我覺得這真是門藝術。

2. 建立 feature list 及 use case diagram

跟客戶聊完天、了解系統要做什麼後建立 feature list,表示整個系統的功能概觀。畫張 use case diagram 呈現使用者或其他系統使用這個系統的藍圖,既然是藍圖,當然不會有太細節的東西啦!feature list 是以功能面的角度看整個系統,use case diagram 則是以「使用」的角度來看整個系統。feature list 裡的功能不管直接或間接,得要能跟 use case diagram 的 use case 互相對應。

Use case diagram example:

到這裡,對整個軟體系統,還只有比較概略性的藍圖,還沒進到 detail,我們要盡可能延後 detail!

Domain Analysis

辨識、收集、組織及表示領域相關資訊的流程,根據既有系統與其開發歷程的研究、領域專家的知識、潛在理論、領域中的新興技術。

是段看不懂在寫什麼的文言文…好吧這種時候我承認原文比較好懂…

在我的理解裡,這部分包含 survey 相關技術,例如 framework 如何使用,包括分析、了解原有架構及既有程式碼、找出相關的物件、物件間關係與互動等等,也包含了解此系統相關的背景知識、相關流程等等,例如要做一個請假系統,得要了解請假流程。

用客戶能理解的語言跟方式描述問題以及系統,不要跟他講什麼 class、variable 就對了。簡單來說──「講人話」。

3. 設計架構

根據 feature list、use case diagram 跟現有程式碼等等資訊將大問題分解成多個各自負責不同功能的 module。組織這些 module 並決定從哪個 module 開始動工。這個階段的重點是建立做事情的順序以及減少風險,更多細節

如果有需要,套用 design pattern。design pattern 是解決特定問題的方式,能結構化程式,讓程式較易被理解、維護而且更有彈性。

4. 一個個處理小功能

將大問題分成許多小問題之後,準備各個擊破啦!

不同的開發方式:Feature driven & Use case driven development

4-1. 想小功能的 requirement,建立 requirement list

依照描述的需求建立需求清單。類似 feature list 的概念,只是小一點,著重在要處理的小功能有何需求,會比最開始的 feature 更進入細節事項。

需求不只包含客戶想要的,也包含當事情不按正常狀況來時系統依然要能正常運作。畢竟客戶通常希望當事情不如預期時,系統仍然能正常運作。可以從兩方面著手:

  1. 這個功能要拿來做什麼、該做什麼?
  2. 在出錯的情況中,系統要做些什麼事?

4-2. 寫 Use case

requirement 及 use case 要能互相對應,跟 feature 與 use case diagram 一樣。

因為系統是跑在真實世界,不是只跑在預期狀況中,要考慮出錯的狀況。但是呢,有時候系統遇到出錯狀況時「如何反應才是正常」不見得是工程師能決定的,所以,請騷擾請教可以決定這件事的人。

更多跟 Use case 有關的細節

4-3. 設計物件細節及物件間的關係

4-4. 實作

運用 OO 原則:

5. 測試

測試所有能想到的可能使用狀況跟不按規矩來的使用狀況。

unit test 已經有抽象上的「功能」觀念。unit test 一次只測一個小功能,但測一個小功能不等於測一個 function,也可能是測很多個 function 組合而成的「功能」。

在測試中要模擬 code 真正被使用的狀況跟情境,而不是測試簡單 call function 但實際上並不會這麼使用的狀況。

Murmur

這只是大通則,裡面很多細節是要依照 project 各自狀況不同有所改變的。雖然說是 OOAD 軟體開發週期,但以概念上來說我覺得前面的需求分析等等跟 OO 沒多大關係。

現在理解到程式設計到處都是 divide and conquer,小時候(?)不懂以為 divide and conquer 只存在 algorithm 裡……

最開始我很容易犯的毛病是一下子就想動手寫 code,然後搞得很崩潰,幾次之後就不會想這麼幹了。還有會一下子就掉進細節而且還出不來,難以維持以 big picture 的角度去看,就整個攪再一起,這點現在到底治好了沒我也不太確定…(欸)

雖然目前我只用到裡面的部分方法,但是似乎有個開發週期的框架後變得比較知道自己在幹嘛,腦子比較不會像果醬糊成一團。

commonality(共通性)跟 variability(變化性)算是觀念,可以套用到軟體開發的不同階段。

在釐清客戶需求的階段,commonality 可以想成軟體「像」什麼,也就是系統需要做的事。variability 則是軟體「不像」什麼,即系統不用處理的事。透過釐清系統像什麼、不像什麼,來了解客戶心中想要的系統究竟要做什麼事。

到了 design 及 implement 階段,分析 class 間的 commonality,可以將共同的部分抽到 base class。

很久很久以前(大概是還在用紙帶打洞的時代),會在 code 裡直接寫 variable 跟 function 所在的 address(我猜一開始說不定只有「要在哪裡取得資料」跟「要跳到哪裡繼續執行」的概念)。增加指令、修改程式後,會有很多 variable 及 function 的 address 被改變,像是中間多塞個指令就會讓後面東西 address 全改了,所以程式中所有 address 都需要重新調整(relocate)。

這種 relocate 工作太令人崩潰,於是有人想出 symbol 的概念──以符號代表某個 variable 或 function(其實就是取名字)。code 裡改用 symbol,不再直接寫 address。等程式要執行的時候再把 symbol 換成真正的 address。這就是最開始 linking 主要做的事。

隨著時代演進(?),程式規模越來越大,人們開始在一個程式中分許多 module 並且分別 compile。有多個 module 後 linking 就要處理跨 module 的 variable 及 function 引用,也就是將在其他 module 中的 variable 跟 function 的 address 填入 reference 到它們的地方。例如在 A module 裡 call B module 的 function foo(),就要在 A module 中填入 foo() 真正的 address。

如此一來,compile 階段可以不用知道 symbol 的 address,而且 module 也可以獨立 compile,等到 link 階段再由 linker 處理 symbol 及 address 的轉換。linker 就像是將多個 compile 好的 module 黏起來。

linking 主要過程:

  • Address and storage allocation
  • Symbol resolution
  • Relocation

object file 是 source code compile 後但尚未 link 的 binary 中間檔,通常跟可執行檔使用相同格式。object file 包含 compile 後的 machine code、data、symbol table、debug 資訊及字串等等。

object file 以不同 section 儲存不同資訊。

Object File Overview

  • File Header 描述檔案屬性、section table
  • .text.code)section 裡放 code
  • .data section 放已經 initialize 的 global varible 及 static local variable
  • .bss section 記錄沒有 initialize 的 variable,先記著「有這個 variable」跟它的 size。但是因為 variable 還沒有 value,所以在 object file 裡不需要浪費空間去記錄 value。

Ref

Executable Format 主要有:

  • Windows 下的 PE(Portable Executable)
  • Linux 下的 ELF(Executable Linkable Format)

其他還有 Intel/Microsoft 的 OMF(Object Module Format)、Unix 的 a.out 以及 MS-DOS COM 格式等等。

除了可執行檔外,Dynamic Linking Library 跟 Static Linking Library 都是以 Executable Format 儲存。

ELF 標準中將使用 ELF 格式的檔案分成:

ELF file type Example
Relocatable File Linux 的 .o、Windows 的 .obj
Executable File /bin/bash、Windows 的 .exe
Shared Object File Linux 的 .so、Windows 的 .dll
Core Dump File Linux 的 core dump

ELF file structure

ELF 檔是由 header、一堆 section 及一堆 table 組成的,各 table 也是 section。

ELF structure

ELF Header

描述整個 ELF 檔的屬性,可用 readelf -h xxx 查看。

struct 定義在 /usr/inclue/elf.hElf32_Ehdr or Elf64_Ehdr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf32_Half e_type; /* Object file type */
Elf32_Half e_machine; /* Architecture */
Elf32_Word e_version; /* Object file version */
Elf32_Addr e_entry; /* Entry point virtual address */
Elf32_Off e_phoff; /* Program header table file offset */
Elf32_Off e_shoff; /* Section header table file offset */
Elf32_Word e_flags; /* Processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size in bytes */
Elf32_Half e_phentsize; /* Program header table entry size */
Elf32_Half e_phnum; /* Program header table entry count */
Elf32_Half e_shentsize; /* Section header table entry size */
Elf32_Half e_shnum; /* Section header table entry count */
Elf32_Half e_shstrndx; /* Section header string table index */
} Elf32_Ehdr;

e_ident 是 magic number 標示這是個 ELF 檔,前 4 個 byte 依序是 0x7f、0x45、0x4c、0x446,接著 3 個 byte 是 “ELF” 三個字母的 ASCII code。所有 ELF 檔前幾個 byte 都是這個內容。除此之外,幾乎所有可執行檔最開始幾個 byte 都是 magic number,供 OS 識別是哪種可執行檔。

e_phoff 表示程式執行時的入口位置,executable file 會填入 address,relocatable file 因為還會進行 relocate 所以值是 0。

從 section header table file offset e_shoff 可以知道 section table 所在位置,由 e_shentsizee_shnum 可以知道 section header table 的 element size 以及總共有多少 element。從 ELF header 可以找到 section header table,由於其他 table 也都是 section,可以再從 section header table 取得所有其他 section 及 table 的資訊。

Section Header Table

描述各 section 的屬性,可用 readelf -S xxx 查看。

一個以 struct Elf32_Shdr(又稱 section descriptor)為 element 的 array,array 的第一個 element 是 NULL,struct 定義在 /usr/include/elf.h。因為 section header table 是個 array,所以 ELF 檔有些地方會以 section 在 section table 中的 index 來 access 或表示該 section。

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct
{
Elf32_Word sh_name; /* Section name (string tbl index) */
Elf32_Word sh_type; /* Section type */
Elf32_Word sh_flags; /* Section flags */
Elf32_Addr sh_addr; /* Section virtual addr at execution */
Elf32_Off sh_offset; /* Section file offset */
Elf32_Word sh_size; /* Section size in bytes */
Elf32_Word sh_link; /* Link to another section */
Elf32_Word sh_info; /* Additional section information */
Elf32_Word sh_addralign; /* Section alignment */
Elf32_Word sh_entsize; /* Entry size if section holds table */
} Elf32_Shdr;

如果一個 section 存在 ELF 檔中,由 sh_offsetsh_size 可以知道其所在位置及大小。section 屬性主要由 section type sh_type 及 section flags sh_flags 決定。

String Table

.strtab 以及 .shstrtab section。

將 ELF 檔裡所用的字串,如 variable name、function name、section name 等存在一個 array 中,以 '\0' 隔開,並以字串在 array 中的 offset 表示該字串。

Symbol Table

.symtab section,可用 readelf -s xxx 查看。

記錄 object file 所用到的 symbol。每個 symbol 有其對應的 symbol value,variable 及 function 的 symbol value 是它們的 address。

symbol table 是以 struct Elf32_Sym 為 element 的 array,Elf32_Sym 一樣定義在 /usr/include/elf.h

1
2
3
4
5
6
7
8
9
typedef struct
{
Elf32_Word st_name; /* Symbol name (string tbl index) */
Elf32_Addr st_value; /* Symbol value */
Elf32_Word st_size; /* Symbol size */
unsigned char st_info; /* Symbol type and binding */
unsigned char st_other; /* Symbol visibility */
Elf32_Section st_shndx; /* Section index */
} Elf32_Sym;

對 linking 較重要的兩種 symbol:global symbol 及 external symbol。global symbol 是定義在此 object file 中並且會讓其他 object file 使用到的 symbol,external symbol 則是此 object file reference 到的其他 object file 中的 symbol。簡單講就是給別人用跟用別人的 symbol,有點繞舌。

Relocation tables

存 relocation 的資訊,.rel.text section。每個需要 relocate 的 section 都會有一個 relocation table。

relocation 可參考 Static Link

Linking View and Execuion View

上述以 section 來劃分 ELF 內容的角度是 Linking View

ELF 在 mapping 到 virtual address space 時是以 page 為單位,如果 section 的大小不是 page 大小的整數倍又以 section 為單位進行 mapping,會浪費許多 memory。load ELF 時 OS 只在乎 section 的屬性如可讀、可寫、可執行,OS 不在乎 section 的內容,為了節省記憶體空間延伸出「將屬性相同的 section 合併成一個 segment,再對應到 virtual address space」的方式。linker 在 link object file 時會盡量將相同屬性的 section 放在一起。

segment 是以 load 的角度劃分 ELF,也就是 Execution View

Ref