2013-03-20 161 views
19

使用特殊的編譯器命令可以聲明一個符號According to Wikipedia弱鏈接的實際應用是什麼?

弱符號在目標文件或動態庫中的符號定義,可以由其他符號覆蓋定義

在什麼情況下或爲了什麼應用程序,你需要弱符號?典型的用例是什麼?

+1

https://ofekshilon.com/2014/02/10/linker-weak-symbols/ – 2016-09-21 09:01:12

回答

15

一個使用弱聯在正在實施更換功能C++標準。即:

void *operator new(std::size_t); 
void *operator new(std::size_t, std::nothrow_t const &) noexcept; 
void *operator new[](std::size_t); 
void *operator new[](std::size_t, const std::nothrow_t&) noexcept; 
void operator delete(void *) noexcept; 
void operator delete(void *, std::nothrow_t const &) noexcept; 
void operator delete[](void *) noexcept; 
void operator delete[](void *, std::nothrow_t const &) noexcept; 

這些都是必須由實現提供的功能,但如果一個程序實現他們則計劃實施替代或覆蓋實現的版本。這很容易通過弱連接來實現。

+0

@BernhardKausler提供了一些相關的SO問題,可能會給出更多的見解:[爲什麼要替換默認的新的和刪除操作符?](http://stackoverflow.com/questions/7149461/why-would-one -replace-default-new-and-delete-operators)[如何正確替換全局new和delete操作符](http://stackoverflow.com/questions/8186018/how-to-properly-replace-global-new-delete [操作符] [我應該如何編寫符合ISO C++標準的自定義新的和刪除操作符?](http://stackoverflow.com/questions/7194127/how-should-i-write-iso-c-standard-conformant-custom-新和刪除運營商) – bames53 2013-03-21 15:03:51

15

在嵌入式開發,當你有例如中斷指針的載體,這是非常方便的,能夠使用弱鏈接獲取默認處理程序打斷你不感興趣的內容。

這是通過定義一個空處理程序(一次),然後爲每個需要的中斷指針引入一個新的正確名稱的符號,該符號與默認處理程序弱連接。

然後,向量被這些符號填充,這些符號都將指向相同的實際代碼,直到您決定使用相同(正確)名稱實現其中的一個名稱,那麼您的代碼會「超負荷」弱鏈接,導致一個指向要安裝在中斷表中的代碼的指針。

這通常是C和彙編的某種混合來實現,但用C僞代碼,我們可能會碰到這樣的:

static void placeholder_isr(void) 
{ 
} 

/* Introduce properly-named function pointers, with weak linking. 
* NOTE: This syntax is completely fictional as far as I know. 
*/ 
void (*timer1_isr)() = placeholder_isr __attribute("weak linking"); 
void (*timer2_isr)() = placeholder_isr __attribute("weak linking"); 
void (*usart1_isr)() = placeholder_isr __attribute("weak linking"); 
void (*usart2_isr)() = placeholder_isr __attribute("weak linking"); 
void (*dma1_isr)() = placeholder_isr __attribute("weak linking"); 
void (*dma1_isr)() = placeholder_isr __attribute("weak linking"); 

/* Declare the table of interrupt handlers. */ 
static void (*isr_table)[] = { 
    timer1_isr, 
    timer2_isr, 
    usart1_isr, 
    usart2_isr, 
    dma1_isr, 
    dma2_isr, 
} __attribute("isr vector"); /* Attribute to place it where it needs to go. */ 

然後在需要時,你可以實現自己的功能:

void timer1_isr(void) 
{ 
    /* Handler ISR from timer1. */ 
} 

而不必改變任何東西,它「只是工作」。當然,只要您的名字是上述「支持代碼」所期望的名稱即可。

5

The weak屬性促使發射作爲一個弱 符號,而不是一個全球性的聲明。這在定義 庫函數時非常有用,它可以在用戶代碼中覆蓋,但 也可以用於非函數聲明。對於ELF目標,弱符號支持 ,對於使用GNU彙編器和鏈接器的 也支持a.out目標。

The weak attribute example

weak.c

extern void foo() __attribute__((weak)); 

int main() { 
if (foo) foo(); 
} 

的foo.c

void foo() { 
printf("in foo.\n"); 
} 

強。ç

extern void foo() ; 

int main() { 
if (foo) foo(); 
} 

編譯

$ cc weak.c // Compiles OK 
$ cc strong.c // undefined reference to `foo' 

當 「foo」 被宣佈爲弱,它的定義可以省略, 或更換不同的庫,具有樣「鏈接時間 綁定」。鏈接器將爲未定義的弱符號填入0。

2

當您希望能夠在代碼的另一部分覆蓋函數定義時,通常使用弱鏈接。這在典型的例如圖書館中就是這種情況。一個默認的錯誤處理程序,如果您使用該庫,您可以使用自定義函數覆蓋該錯

4

典型的和每一天的用例都是內聯和模板函數。

例如這部分代碼時g++ -shared -fPIC編譯:

extern void a(); 

inline void foo() { a(); } 

void bar() { foo(); } 
void baz() { foo(); } 

本來符號bar和baz通過nm標記爲T(正常)和Foo將被標記爲W - 弱。

(即mn -C ./a.out

理由:

內聯函數和模板可以在報頭中定義和通常來源的不同部分定義的多個次,最後只有一個保持活動狀態。

如果將未標記爲弱,將是多個「foo」的符號碰撞或編譯器將無法禁用內聯

+0

因此,大多數模板函數也很弱。 – 2013-03-20 15:15:08

+0

@MatthieuM。的確,添加到答案 – Artyom 2013-03-20 19:32:25