uClinux移植和分析 2

2021-04-12 11:42:26 字數 2454 閱讀 6738

printf和標準輸出

上次寫到main函式的引數傳遞.現在繼續往下進行.最近忙實驗室的事情,看了一周的文章,也沒啥進展,週末寫點技術貼,放鬆一下:-)

進入main函式後,就要呼叫printf("hello world!/n");了.順便將c語言引數傳遞提一下.字串"hello world!/n"編譯器是當作字串常量來處理的,雖然printf是在main內部呼叫,但"hello world!/n"可不是放在main的棧中,字串常量至少是放到.data段的,準確說是放在唯讀資料段.rodata,這個我在工作站上驗證了一 把.假如編輯的檔名是hello.c,首先編譯生成elf格式二進位制檔案gcc hello.c -o hello然後用命令objdump -s hello -s引數會將所有段資訊dump出來.你會看到"hello world!/n"位於.rodata段.

printf()是個標準c庫函式.雖然功能簡單,但實現起來卻不容易.這是個和平台相關的函式.在pc上,printf輸出是輸出到終端螢幕,在嵌入式 裝置上,一般printf()是輸出到串列埠.同是呼叫printf(),最終輸出的裝置卻不同,從直覺的肯定是感覺printf()底層和平台是相關的. 那麼printf()是怎樣實現的呢?

可以看一下c庫程式的**,這裡以uclibc為例.

int printf(const char * __restrict format, ...)

printf支援字串格式化輸出,具體引數處理這裡不提.可以看到printf()呼叫了vfprintf(),vfprintf()第乙個引數是stdout是標準輸出裝置.標準輸出裝置是個結構體,最重要的成員就是他的描述符,其值為1.

跟進vfprintf()函式看,裡面是複雜的引數處理,因為printf()的引數形式很靈活,所以在vfprintf()裡面要對傳進來的引數進行解 析處理,形成最終的輸出格式.有興趣的可以看一下,借助這個可以讓你在乙個沒有作業系統的平台上實現你自己的printf()函式.這樣你在裸機上調程式 時輸出除錯資訊就更方便些(實際上uclinux的printk就是這麼幹的).

vfprintf()在引數處理之後,就是輸出了,輸出呼叫的是putc(),進入putc()然後再跟進幾層函式,發現呼叫了linux系統呼叫 write()。呵呵,是的,輸出就是借助作業系統**完成的。在write之前所有的**都是c庫的**,可以說是和平台無關的。而涉及到具體輸出,就 要呼叫作業系統提供給你的介面。系統呼叫的原理就是通過一定手段(一般是trap陷阱)進入作業系統的核心空間,呼叫作業系統**來完成某些任務。

linux系統呼叫針對不同平台有不同的實現方式。這個以後再講。呼叫write()後,進入核心空間,首先來到的就是sys_write(),這個函式 **位於fs/read_write.c中。一進入sys_write(),就要根據傳進來的fd描述符找到相應的file結構。對於標準輸出,fd= 1,每個程序的程序控制塊都有乙個開啟檔案的陣列。file結構就是根據fd在這個陣列中查詢到相應的結構。找到結構後,就會呼叫file-> write()來向外輸出。具體輸出到**,就要看file結構對應的裝置驅動是什麼。一般嵌入式系統可以從串列埠將資訊輸出,那麼file-> write()最底層就是呼叫的串列埠驅動的類似tran**it_char的函式。

有關linux的裝置驅動有很多書介紹,整個驅動的結構很複雜,我這裡也沒必要提了.至於終端裝置怎樣掛在驅動佇列裡面,怎麼根據標準輸出的描述符找到相 應的驅動結構有興趣的莊printf()函式看,裡面是複雜的引數處理,因為printf()的引數形式很靈活,所以在vfprintf()裡面要對傳進 來的引數進行解析處理,形成最終的輸出格式.有興趣的可以看一下,借助這個可以讓你在乙個沒有作業系統的平台上實現你自己的printf()函式.這樣你 在裸機上調程式時輸出除錯資訊就更方便些(實際上uclinux的printk就是這麼幹的).

vfprintf()在引數處理之後,就是輸出了,輸出呼叫的是putc(),進入putc()然後再跟進幾層函式,發現呼叫了linux系統呼叫 write()。呵呵,是的,輸出就是借助作業系統**完成的。在write之前所有的**都是c庫的**,可以說是和平台無關的。而涉及到具體輸出,就 要呼叫作業系統提供給你的介面。系統呼叫的原理就是通過一定手段(一般是trap陷阱)進入作業系統的核心空間,呼叫作業系統**來完成某些任務。

linux系統呼叫針對不同平台有不同的實現方式。這個以後再講。呼叫write()後,進入核心空間,首先來到的就是sys_write(),這個函式 **位於fs/read_write.c中。一進入sys_write(),就要根據傳進來的fd描述符找到相應的file結構。對於標準輸出,fd= 1,每個程序的程序控制塊都有乙個開啟檔案的陣列。file結構就是根據fd在這個陣列中查詢到相應的結構。找到結構後,就會呼叫file-> write()來向外輸出。具體輸出到**,就要看file結構對應的裝置驅動是什麼。一般嵌入式系統可以從串列埠將資訊輸出,那麼file-> write()最底層就是呼叫的串列埠驅動的類似tran**it_char的函式。

有關linux的裝置驅動有很多書介紹,整個驅動的結構很複雜,我這裡也沒必要提了.至於終端裝置怎樣掛在驅動佇列裡面,怎麼根據標準輸出的描述符找到相應的驅動結構有興趣的請查閱相關資料.

uclinux移植遇到的問題

但是遇到了一些問題 重起後,導致了出現 檔案的錯誤,不能用我的使用者名稱進行登入,搜尋網路後發現這個問題經常有人遇到,解決方法是登入到 然後執行 命令。或者 home username 我試了這兩種方法,不知道到底是哪個起作用了,再重啟的時候不再出現 dmrc 的錯誤,但是出現了更嚴重的 持續不到 ...

基於uClinux的NPTL執行緒庫移植

2007 12 25 09 56 29 摘要 在linux2.6中,nptl native posix thread library 已取代linuxthreads成為glibc的首選執行緒庫,但是在嵌入式作業系統中普遍使用的基於posix 標準的執行緒庫仍是linuxthreads。分析了nptl...

UBOOT的移植分析2

uboot的移植分析2 a uboot的編譯方式2 1 原地編譯 編譯複雜專案 makefile提供2種編譯管理的方法,預設情況下編譯出來的資料夾 的.c和.o檔案是存放在這些目錄裡面的,就是預設情況下編譯出來的情況,但是我們 有些時候並不希望生成的.o檔案把整個資料夾汙染了 壞處 1 汙染了原始檔...