c语言sin函数返回nan,C语言入口函数和LD_PRELOAD环境变量
零.C語言入口函數
從第一天學習C語言開始,我們的腦子里就深深烙下這樣一個概念:C語言程序總是從main()函數開始執行,main()函數結束,程序也就結束了.在平時的練習中貌似這沒有問題,但事實真的是這樣嗎?測試一下,
點擊(此處)折疊或打開
#include
#include
#include
int enter(void)
{
printf("the start function!\n");
return 0;
}
編譯:
打印處一頁錯誤,其中有這樣一條:
crt1.o:In function `__start':(.text+0x20): undefined reference to `main'
字面翻譯就是:在函數_start中,main沒有定義. __start函數是什么?main還要定義?crtl.o又是什么?帶著疑問,我打開了百度.在其中搜到這樣一份偽代碼:
section .text:
__start:
:
init stack;
init heap;
open stdin;
open stdout;
open stderr;
:
push argv;
push argc;
call _main; (調用 main)
:
destory heap;
close stdin;
close stdout;
close stderr;
:
call __exit;
終于找到了,原來main就躲在crt1.o中,再看__start函數,"start"?不是開始的意思嗎?難道每一個C程序就是從這開始的嗎?
原來,對于“crt1.o”這個文件,其中crt是“C runtime library”的縮寫,其含義是“C運時庫”,C運行時庫除了給我們提供必要的庫函數調用(如memcpy、printf、malloc等)之外,它提供的另一個最重要的功能是為應用程序 添加啟動函數。C運行時庫啟動函數的主要功能為 進行程序的初始化 ,對全局變量進行賦初值 ,加載用戶程序的入口函數 。
soga,那這是不是意味著我們可以修改所要加載的入口函數呢?原來還有這樣一條命令:
gcc *.c -e -nostartfiles
其中, *.c 為程序的源文件,-e為修改函數的入口地址,e == entrance ,后面的 就指明要替換的函數,-nostartfiles選項的作用是 通知編譯器不自動加入啟動函數以及別的庫級別的初始化 ,這樣就不會調用到crt1.o中的_start函數!測試一下,
點擊(此處)折疊或打開
#include
#include
#include
int enter(void)
{
printf("the start function!\n");
return 0;
}
編譯通過,運行:
the start function!
段錯誤 (核心已轉儲)
成功運行enter函數,但提示了段錯誤.
原來,在編譯的時候加上了-nostartfiles這個選項的同時,使得最后的return語句不能正常執行。解決方案是,把程序最后的return語句改成exit()函數,因為return是將控制權交給調用函數,此時我們已經沒有調用__start這個函數了,自然就沒有enter的調用函數,然而exit()函數是將控制權交給內核,所以能夠成功退出.
運行結果:
the start function!
一.LD_PRELOAD
在將LD_PRELOAD之前,我們先來了解一下兩種鏈接方式
靜態鏈接:由鏈接器在 鏈接時 將庫的內容加入到可執行程序中.
動態鏈接:在可執行文件 裝載時或運行時(注意與靜態鏈接的區別) ,由操作系統的裝載程序加載庫.
通俗地講,一種是無論程序運行與否,都加載庫(靜態庫);另一種是只有執行到那一部分代碼時,才加載庫(動態庫).
在Linux的動態鏈接庫的世界中,LD_PRELOAD就是這樣一個環境變量,它可以影響程序的運行時的鏈接(Runtime linker),它允許你定義 在程序運行前 優先加載的動態鏈接庫 .這個功能主要就是用來有選擇性的載入不同動態鏈接庫中的相同函數 .通過這個環境變量,我們可以 在主程序和其動態鏈接庫的中間加載別的動態鏈接庫 ,甚至覆蓋正常的函數庫.
說了這么多,是不是有點模糊?舉個例子,
首先先編寫一個“strcmp”函數,就將它命名為passwd.c
點擊(此處)折疊或打開
#include
int strcmp(const char *str1,const char *str2)
{
puts(str1);
puts(str2);
return 0;
}
執行下面的語句:
gcc passwd.c -shared -o passwd.so -fPIC
其中,-shared選項的意思是將passwd.c編譯鏈接成為一個動態庫.*.so在Linux中為共享庫——shared object,用于動態鏈接,和Windows下的dll差不多.
在shell中執行程序時,shell會提供一組環境變量.其中export的作用就是新增一個環境變量,供后續執行的程序使用.export的效力僅及于該此登陸操作.
對于-fPIC,-f后面跟一些編譯選項,PIC是其中一種,表示生成位置無關代碼(Position Independent Code),位置無關碼就是可以在進程的任意內存位置執行的目標碼,動態鏈接庫必須使用.
然后,我們就用passwd.so這個庫來進行優先替換:
export LD_PRELOAD=./passwd.so
我們知道,strcmp()的功能是比較兩個字符串,但是在這里我們用passwd.so來代替系統的動態庫,測試一下,
點擊(此處)折疊或打開
#include
#include
#include
int main(int argc, char *argv[])
{
char *str = "abcdef";
char pass[10];
printf("Please input the passwd:\n");
gets(pass);
if( strcmp(pass,str) == 0 )
{
printf("Login succeed!\n");
}
else
{
printf("Passwd incorrect!\n");
exit(0);
}
return 0;
}
運行結果:
Please input the passwd:
123456
123456
abcdef
Login succeed!
就這樣,strcmp()成功被我們替換了...
參考博文---------------------http://blog.sina.com.cn/s/blog_76a864e20101ehuz.html
總結
以上是生活随笔為你收集整理的c语言sin函数返回nan,C语言入口函数和LD_PRELOAD环境变量的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux文件属性是什么意思,Linux
- 下一篇: jboss mysql驱动目录_找不到m