亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關于我們
? 蟲蟲下載站

?? 漫談兼容內核之七:wine的二進制映像裝入和啟動.txt

?? 漫談系統內核內幕 收集得很辛苦 呵呵 大家快下在吧
?? TXT
?? 第 1 頁 / 共 4 頁
字號:
漫談兼容內核之七:Wine的二進制映像裝入和啟動

[b][size=4][align=center]漫談兼容內核之七:Wine的二進制映像裝入和啟動[/align][/size][/b]
[align=center]毛德操[/align]

    上一篇漫談中介紹了幾種二進制可執行映像的識別方法,而識別的目的當然是為了要裝入并啟動這些映像的執行。映像的裝入和啟動一般總是和創建進程相連系,所以本來就是個相當復雜的過程。而對于Wine,則在進程創建方面又增添了一些額外的復雜性。
    為什么呢?我們這樣來考慮:在Windows或ReactOS中,創建進程是由CreateProcessW()完成的,系統中的“始祖”進程就是個Windows進程,代代相傳下來,總是由Windows進程創建Windows進程,所以映像的裝入和啟動只發生在CreateProcessW()中,所裝入的也總是Windows或DOS上的二進制映像。而在Linux中,所謂“創建進程”實際上是將一個線程轉化成進程,這是由execve()一類的系統調用完成的,那也只是Linux進程的代代相傳,所裝入的也總是Linux上的二進制映像,包括a.out和ELF映像。
    可是Wine就不同了。Wine是在Linux內核上運行,系統里的“始祖”進程是Linux進程,但是卻需要由作為其后代的Linux進程創建出Windows進程來。另一方面,創建出來的Windows進程則有可能通過CreateProcessW()再創建新一代的Windows進程(實際上Wine還允許Windows進程創建Linux進程,這我們就不說了)。
    兼容內核則與Wine相似,也有“從Linux到Windows”和“從Windows到Windows”兩種不同的進程創建。那么,在這兩種條件下的映像裝入是否也有明顯的區別呢?就Wine而言,這兩種進程創建(從而映像裝入)都是在Linux環境下在內核外面實現,區別應該是不大的。至于真正的從Windows到Windows的進程創建和映像裝入,則應該再到ReactOS中去尋找借鑒。所以我們最好要分別考察Wine和ReactOS兩個系統的進程創建和映像裝入。在這篇漫談中我們先考察Wine系統中的映像裝入,而Wine系統中的映像裝入又分兩種,一種是在Linux環境下通過鍵盤命令啟動一個Windows應用程序,另一種是由一個Windows應用程序通過CreateProcessW()再創建一個Windows進程。

    應該說,Wine的映像裝入和啟動的過程是相當復雜的。要了解這個過程,我們不妨從一些裝入工具著手,所以我們通過目錄wine/loader下面的幾個源碼文件來說明問題。在這幾個文件中,有兩個.c文件是有main()函數的。一個是main.c,另一個是glibc.c。編譯/連接以后,glibc.c中的main()進入工具wine,而main.c中的main()則分別進入wine-kthread和wine-pthread兩個工具。在功能上wine-kthread和wine-pthread二者的作用是一樣的,只是后者依靠程序庫libpthread.a實現和管理線程,而前者則直接依靠內核實現和管理線程。另外還有一個文件preloader.c,雖然并不帶有函數main(),但是編譯/連接以后也成為一個可以獨立運行的工具wine-preloader。

    我們先看由Linux的shell啟動執行一個Windows應用軟件的過程。
    實際上Windows應用并不是由Linux的Shell直接啟動的,而是通過一條類似于“wine notpad.exe”的命令由Shell啟動Wine的裝入/啟動工具wine,再由wine間接地裝入/啟動具體的應用程序。整個過程要依次經由wine、wine-preloader、以及wine-kthread或wine-pthread共三個工具軟件的接力才能完成。我們就順著這個軌跡從wine開始。
    可執行程序wine的入口main()在loader/glibc.c中(不是在main.c中!)。

[code]int main( int argc, char *argv[] )
{
    const char *loader = getenv( "WINELOADER" );
    const char *threads = get_threading();

    if (loader)
    {
        const char *path;
        char *new_name, *new_loader;

        if ((path = strrchr( loader, '/' ))) path++;
        else path = loader;

        new_name = xmalloc( (path - loader) + strlen(threads) + 1 );
        memcpy( new_name, loader, path - loader );
        strcpy( new_name + (path - loader), threads );

        /* update WINELOADER with the new name */
        new_loader = xmalloc( sizeof("WINELOADER=") + strlen(new_name) );
        strcpy( new_loader, "WINELOADER=" );
        strcat( new_loader, new_name );
        putenv( new_loader );
        wine_exec_wine_binary( new_name, argv, NULL, TRUE );
    }
    else
    {
        wine_init_argv0_path( argv[0] );
        wine_exec_wine_binary( threads, argv, NULL, TRUE );
    }
    fprintf( stderr, "wine: could not exec %s\n", argv[0] );
    exit(1);
}[/code]
    先由getenv()檢查是否已經設置了環境變量WINELOADER,如已設置則getenv()返回其定義,否則返回0。下面就可看到,檢查的目的其實只是為了將其設置正確。接著的get_threading()則是為了確定是否在使用libpthread,從而確定下一步應該使用wine-kthread還是wine-pthread。這二者之間的選擇與線程的實現模式有關,pthread中的’p’表示Posix,而kthread中的’k’表示Kernel。不過這是個專門的話題,在這里就不深入下去了,只是說明我們一般都使用kthread,因此這個函數一般返回字符串“wine-kthread”,于是字符串threads的值就是“wine-kthread”。
    如果環境變量WINELOADER有定義,即loader非0,就要把該變量的值設置成threads的值。但是WINELOADER的值很可能包含著整個路徑,所以需要先進行一些字符串的處理,把threads的值與原來的目錄路徑拼接在一起。然后就是關鍵所在、即對于函數wine_exec_wine_binary()的調用了。
    如果環境變量WINELOADER沒有定義,那就不需要去設置它了。但是這里通過wine_init_argv0_path()設置了argv0_path和argv0_name兩個靜態變量,然后也是對函數wine_exec_wine_binary()的調用。
    總之,wine_exec_wine_binary()是這里的關鍵。讀者下面就會看到,對這個函數的調用要是成功就不會返回。此外,注意在這里調用這個函數時的最后一個參數都是TRUE。

[code][main() > wine_exec_wine_binary()]

/* exec a wine internal binary (either the wine loader or the wine server) */
void wine_exec_wine_binary( const char *name, char **argv, char **envp, int use_preloader )
{
    const char *path, *pos, *ptr;

    if (name && strchr( name, '/' ))
    {
        argv[0] = (char *)name;
        preloader_exec( argv, envp, use_preloader );
        return;
    }
    else if (!name) name = argv0_name;

    /* first, try bin directory */
    argv[0] = xmalloc( sizeof(BINDIR "/") + strlen(name) );
    strcpy( argv[0], BINDIR "/" );
    strcat( argv[0], name );
    preloader_exec( argv, envp, use_preloader );
    free( argv[0] );

    /* now try the path of argv0 of the current binary */
    . . . . . .

    /* now search in the Unix path */
    . . . . . .
}[/code]
    在我們這個情景中,這里的參數name是“wine-kthread”,參數use_preloader是TRUE,而argv[]數組中各項則依次是“wine”和“notepad.exe”,相當于命令行“wine notepad.exe”。這里實質性的操作顯然是preloader_exec()。但是在調用preloader_exec()之前把argv[0]換成了“wine-kthread”。這樣,對于傳給preloader_exec()的argv[],與其相當的命令行就變成了“wine-kthread  notepad.exe”。當然,這是在為執行另一個工具wine-kthread作準備。
    如果原來的argv[0]是個路徑,那就把程序名wine替換掉以后加以調用就是。而如果只是個程序名而并不包括目錄路徑的話,那就要反復嘗試,首先是目錄/usr/local/bin,然后是當前目錄,在往下就是逐一嘗試環境變量PATH中定義的各個路徑。在正常的情況下,preloader_exec()是不返回的(所以wine_exec_wine_binary()不返回),如果返回就說明在給定的目錄中找不到wine-kthread。所以,要是逐一嘗試全都失敗的話,wine_exec_wine_binary()就會返回而在main()中顯示出錯信息。
    接著往下看preloader_exec()的代碼。

[code][main() > wine_exec_wine_binary() > preloader_exec()]

/* exec a binary using the preloader if requested; helper for wine_exec_wine_binary */
static void preloader_exec( char **argv, char **envp, int use_preloader )
{
#ifdef linux
    if (use_preloader)
    {
        static const char preloader[] = "wine-preloader";
        char *p, *full_name;
        char **last_arg = argv, **new_argv;

        if (!(p = strrchr( argv[0], '/' ))) p = argv[0];
        else p++;

        full_name = xmalloc( p - argv[0] + sizeof(preloader) );
        memcpy( full_name, argv[0], p - argv[0] );
        memcpy( full_name + (p - argv[0]), preloader, sizeof(preloader) );

        /* make a copy of argv */
        while (*last_arg) last_arg++;
        new_argv = xmalloc( (last_arg - argv + 2) * sizeof(*argv) );
        memcpy( new_argv + 1, argv, (last_arg - argv + 1) * sizeof(*argv) );
        new_argv[0] = full_name;
        if (envp) execve( full_name, new_argv, envp );
        else execv( full_name, new_argv );
        free( new_argv );
        free( full_name );
        return;
    }
#endif
    if (envp) execve( argv[0], argv, envp );
    else execv( argv[0], argv );
}[/code]
    當然,條件編譯控制量linux是有定義的,而參數use_preloader則為TRUE。這里實質性的操作是系統調用execve()或execv(),視調用參數envp是否為非0、即是否需要傳遞環境變量而定。但是這是一段有點“奧妙”的代碼。奧妙之處是把原來的argv[]擴大成了new_argv[],使原來的argv[0]變成了new_argv[1],而new_argv[0]則固定設置為“wine-preloader”,并保持原有的目錄路徑不變。由于傳給execve()或execv()的是new_argv[],這就相當于在命令行“wine-kthread  wine notepad.exe”前面添上了一項,變成了這樣(如果忽略目錄路徑):
    “wine-preloader  wine-kthread  wine notepad.exe”
    這就是說,本來是要啟動裝入工具wine-kthread,現在卻變成了wine-preloader,而原來的命令行則變成了傳給wine-preloader的命令行參數。
限于篇幅,這里就不介紹Linux內核如何裝入ELF格式可執行映像的過程了。只是指出:wine-preloader是個ELF格式的可執行映像,但這是個特殊的ELF可執行映像。特殊在哪里呢?可以看一下Makefile中對于如何編譯/連接這個程序的說明:

[code]wine-preloader: preloader.o Makefile.in
$(CC) -o $@ -static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x78000000 preloader.o \
$(LIBPORT) $(LDFLAGS)[/code]
    注意這里的連接可選項-nostartfiles和-nodefaultlibs,這說明在連接時不使用通常都要使用的C程序庫。那么,C程序庫中都有些什么函數呢?有些是大家都很熟悉的。例如printf(),malloc()等等,再如C庫對系統調用的包裝open()、read()、 mmap()等等,就是大家所熟知的。但是還有一些則知道的人不多,現在就涉及到這些函數了。
    大家知道C程序的總入口是main(),可是這只是就程序設計而言。其實操作系統內核在裝入可執行映像以后最初跳轉進入的是一個名為_start()的函數。是這個函數為main()和其余目標程序的運行做好各種準備、即系統層次上的初始化,然后再調用main()的。不管用戶程序是什么樣,干什么事,這一部分的操作都是一樣的,所不同的只是一些參數(例如程序段和數據段的大小和位置等等),而這些參數都存放在具體可執行映像的頭部。這樣,與此有關的代碼就不需要由用戶的程序員來反復地編寫,而是統一放在C庫中供大家連接使用。正因為如此,_start()對于一般的程序員是不可見的,因而也就不為人所知了。而main()之所以是“總入口”,只是因為標準C庫中的有關程序總是在完成初始化以后調用main()。對于wine-preloader,上述可選項的作用就是告訴連接程序ld,讓它別用C庫,而由preloader.c自己來提供_start()。既然preloader.c中的_start()是自己寫的,當然就有了自由度,而不必使用main()這個函數名了,這就是preloader.c中沒有main()的原因。
    另一方面,對于映像裝入內存后的地址也作了明文規定,就是從0x78000000開始。
    不光是wine-preloader特殊,wine-kthread和wine-pthread的編譯/連接也有點特殊,它們的裝入地址是可以浮動的。雖然它們各自都有個main(),實際上卻接近于共享庫、即.so模塊。
    對于wine-preloader,我們從_start()開始看它的代碼。這是一段匯編代碼。

[code]__ASM_GLOBAL_FUNC(_start,
                  "\tmovl %esp,%eax\n"
                  "\tleal -128(%esp),%esp\n"  /* allocate some space for extra aux values */
                  "\tpushl %eax\n"           /* orig stack pointer */
                  "\tpushl %esp\n"           /* ptr to orig stack pointer */
                  "\tcall wld_start\n"
                  "\tpopl %ecx\n"            /* remove ptr to stack pointer */
                  "\tpopl %esp\n"            /* new stack pointer */
                  "\tpush %eax\n"           /* ELF interpreter entry point */
                  "\txor %eax,%eax\n"

?? 快捷鍵說明

復制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
免费欧美日韩国产三级电影| 激情欧美一区二区| 日韩精品一区二区三区四区| 国产999精品久久| 亚洲国产中文字幕在线视频综合| 成人国产亚洲欧美成人综合网| 日韩久久一区二区| 精品少妇一区二区三区在线播放| 成人黄色电影在线 | 国产精品一级二级三级| 亚洲欧美日韩国产综合在线| 日韩美女在线视频| 在线观看不卡一区| 波多野结衣一区二区三区| 麻豆成人免费电影| 亚洲国产视频一区| 中文字幕中文字幕一区| 欧美精品一区二区三区四区 | 亚洲欧美电影一区二区| 精品91自产拍在线观看一区| 精品视频一区二区三区免费| 白白色 亚洲乱淫| 国产ts人妖一区二区| 九九视频精品免费| 免费在线一区观看| 日韩高清一区二区| 五月天一区二区| 成人免费视频一区| 黑人巨大精品欧美一区| 日本三级韩国三级欧美三级| 亚洲一区二区三区爽爽爽爽爽| 国产三级一区二区三区| 欧美成人一区二区三区| 欧美一卡二卡在线| 日韩欧美亚洲一区二区| 日韩视频免费直播| 日韩欧美一二三四区| 欧美电视剧在线观看完整版| 欧美一级欧美三级| 日韩欧美久久久| 欧美不卡一二三| 精品国产99国产精品| 欧美mv日韩mv国产网站| 久久亚洲捆绑美女| 国产亚洲成aⅴ人片在线观看 | 久久综合成人精品亚洲另类欧美 | 国产一区二区三区久久久| 蜜臀av亚洲一区中文字幕| 麻豆中文一区二区| 极品美女销魂一区二区三区免费| 日韩极品在线观看| 青娱乐精品视频在线| 日韩av在线发布| 九色|91porny| 成人综合婷婷国产精品久久免费| 国产剧情在线观看一区二区| 国产乱人伦精品一区二区在线观看| 色综合久久中文综合久久97 | 欧美福利视频导航| 日韩你懂的在线观看| www久久精品| 国产午夜亚洲精品理论片色戒 | 欧美性视频一区二区三区| 欧美亚洲综合网| 欧美夫妻性生活| 精品久久久久久久久久久院品网| 精品99久久久久久| 中文字幕在线播放不卡一区| 一区二区三区欧美| 美女视频网站久久| 国产91色综合久久免费分享| 91视频精品在这里| 欧美一区二区三区系列电影| 久久一区二区三区国产精品| 国产精品久久午夜夜伦鲁鲁| 亚洲国产日韩一级| 裸体一区二区三区| 不卡一卡二卡三乱码免费网站 | 欧美精三区欧美精三区| 久久先锋影音av鲁色资源网| 中文字幕欧美一区| 秋霞午夜av一区二区三区| 国产精一品亚洲二区在线视频| 久久久久久久久久久久久夜| 中文字幕制服丝袜成人av| 午夜免费久久看| 国产福利视频一区二区三区| 在线免费观看日本欧美| 精品999在线播放| 亚洲图片欧美综合| 丁香婷婷综合色啪| 91麻豆精品国产91| 中文字幕在线不卡| 久久超级碰视频| 日本精品裸体写真集在线观看| 在线不卡欧美精品一区二区三区| 久久综合九色欧美综合狠狠| 亚洲一二三区视频在线观看| 国产成人自拍网| 337p亚洲精品色噜噜| 自拍偷拍国产精品| 九九精品一区二区| 欧美日韩一区小说| 国产精品嫩草影院com| 麻豆成人久久精品二区三区红| 成人天堂资源www在线| 日韩欧美久久久| 亚洲一区二区四区蜜桃| 波多野结衣在线一区| 日韩精品中文字幕一区二区三区| 最新热久久免费视频| 国产毛片精品国产一区二区三区| 欧美无砖专区一中文字| 中文字幕一区二区三区蜜月| 久久99精品久久久久久动态图| 色94色欧美sute亚洲线路一久| 精品国产3级a| 美女脱光内衣内裤视频久久网站 | 日韩一二三区视频| 亚洲综合精品久久| 91偷拍与自偷拍精品| 国产精品无码永久免费888| 国产一区二区三区在线看麻豆| 日本韩国视频一区二区| 国产精品欧美一级免费| 国产1区2区3区精品美女| 2023国产精品| 国内成人免费视频| 欧美成人a∨高清免费观看| 蜜桃久久av一区| 欧美一区二区二区| 欧美a级理论片| 欧美一级一级性生活免费录像| 一区二区三区不卡视频| 色综合久久久久久久久久久| 综合欧美亚洲日本| 91亚洲大成网污www| ...xxx性欧美| 91麻豆精品在线观看| 亚洲精品videosex极品| 99精品热视频| 亚洲男女一区二区三区| 色88888久久久久久影院按摩| 国产精品剧情在线亚洲| 92精品国产成人观看免费| 亚洲天堂a在线| 欧美性猛交xxxxxx富婆| 亚洲一区二区在线免费观看视频| 色成年激情久久综合| 亚洲与欧洲av电影| 欧美老肥妇做.爰bbww视频| 日本中文字幕一区二区视频| 欧美一区二区三区视频免费 | 欧美日韩一级大片网址| 亚洲成国产人片在线观看| 69成人精品免费视频| 蜜桃精品视频在线| 中文字幕av免费专区久久| 99re8在线精品视频免费播放| 亚洲日本va午夜在线影院| 欧美日韩一区久久| 久久99国内精品| 国产精品久久久久影院色老大| 菠萝蜜视频在线观看一区| 亚洲第一成人在线| 精品国产麻豆免费人成网站| 成人精品在线视频观看| 一级女性全黄久久生活片免费| 欧美四级电影网| 91国产精品成人| 激情亚洲综合在线| 国产精品国产三级国产a | 国产精品亚洲专一区二区三区| 欧美精品一区二区三区蜜桃视频| 国产美女在线精品| 亚洲欧美日韩中文字幕一区二区三区 | 国产精品午夜久久| 91麻豆swag| 久久精品国产99| 欧美国产成人在线| 欧美区视频在线观看| 国产一二三精品| 亚洲成国产人片在线观看| 久久综合久色欧美综合狠狠| 色诱亚洲精品久久久久久| 精品亚洲欧美一区| 亚洲美女免费在线| www成人在线观看| 欧美色电影在线| 国产成人亚洲综合a∨猫咪| 伊人色综合久久天天人手人婷| 欧美日韩高清影院| av激情成人网| 精品在线播放免费| 亚洲福利视频导航| 中文字幕一区在线观看视频| 欧美大片拔萝卜| 欧美日韩一区二区三区在线| 成人自拍视频在线观看| 日韩av一区二区三区四区|