日B视频 亚洲,啪啪啪网站一区二区,91色情精品久久,日日噜狠狠色综合久,超碰人妻少妇97在线,999青青视频,亚洲一区二卡,让本一区二区视频,日韩网站推荐

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

從進程啟動是怎么一步步到main函數(shù)的

strongerHuang ? 來源:strongerHuang ? 作者:軒轅之風 ? 2020-11-03 15:51 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

首先先劃定一下這個問題的討論范圍:C/C++語言

這篇文章主要討論的是操作系統(tǒng)層面上對于進程、線程的創(chuàng)建初始化等行為,而像Python、Java等基于解釋器、虛擬機的語言,如何進入到main函數(shù)執(zhí)行,這背后的路徑則更長(包含了解釋器和虛擬機內部的執(zhí)行流程),以后有機會再討論。所以這里就重點關注C/C++這類native語言的main函數(shù)是如何進入的。

本文會兼顧敘述Linux和Windows兩個主要平臺上的詳細流程。

創(chuàng)建進程

第一步,創(chuàng)建進程。

在Linux上,我們要啟動一個新的進程,一般通過fork+exec系列函數(shù)來實現(xiàn),前者將當前進程“分叉”出一個孿生子進程,后者負責替換這個子進程的執(zhí)行文件,來執(zhí)行子進程的新程序文件。

這里的fork、exec系列函數(shù),是操作系統(tǒng)提供給應用程序的API函數(shù),在其內部最終都會通過系統(tǒng)調用,進入操作系統(tǒng)內核,通過內核中的進程管理機制,來完成一個進程的創(chuàng)建。

操作系統(tǒng)內核將負責進程的創(chuàng)建,主要有下面幾個工作要做:

創(chuàng)建內核中用于描述進程的數(shù)據(jù)結構,在Linux上是task_struct

創(chuàng)建新進程的頁目錄、頁表,用于構建新進程的內存地址空間

在Linux內核中,由于歷史原因,Linux內核早期并沒有線程的概念,而是用任務:task_struct來描述一個程序的執(zhí)行實例:進程。

在內核中,一個任務對應就是一個task_struct,也就是一個進程,內核的調度單元也是一個個的個task_struct。

后來,多線程的概念興起,Linux內核為了支持多線程技術,task_struct實際上表示的變成了一個線程,通過將多個task_struct合并為一組(通過該結構內部的組id字段)再來描述一個進程。因此,Linux上的線程,也稱為輕量級進程。

系統(tǒng)調用fork的一個重要使命就是要去創(chuàng)建新進程的task_struct結構,創(chuàng)建完成后,進程就擁有了調度單元。隨后將開始可以參與調度并有機會獲得執(zhí)行。

加載可執(zhí)行文件

通過fork成功創(chuàng)建進程后,此時的子進程和父進程相當于一個細胞進行了有絲分裂,兩個進程“幾乎”是一模一樣的。

而要想子進程執(zhí)行新的程序,在子進程中還需要用到exec系列函數(shù)來實現(xiàn)對進程可執(zhí)行程序的替換。

exec系列函數(shù)同樣是系統(tǒng)調用的封裝,通過調用它們,將進入內核sys_execve來執(zhí)行真正的工作。

這個工作細節(jié)比較多,其中有一個重要的工作就是加載可執(zhí)行文件到進程空間并對其進行分析,提取出可執(zhí)行文件的入口地址。

我們使用C、C++等高級語言編寫的代碼,最終通過編譯器會編譯生成可執(zhí)行文件,在Linux上,是ELF格式,在Windows上,稱之為PE文件。

無論是ELF文件還是PE文件,在各自的文件頭中,都記錄了這個可執(zhí)行文件的指令入口地址,它指示了程序該從哪里開始執(zhí)行。

這個入口指向哪里,是我們的main函數(shù)嗎?這里賣一個關子,先來解決在這之前的一個問題:進程創(chuàng)建后,是如何來到這個入口地址的?

不管在Windows還是Linux上,應用線程都會經常在用戶空間和內核空間來回穿梭,這可能出現(xiàn)在以下幾種情況發(fā)生時:

系統(tǒng)調用

中斷

異常

從內核返回時,線程是如何知道自己從哪里進來的,該回到應用空間的哪里去繼續(xù)執(zhí)行呢?

答案是,在進入內核空間時,線程將自動保存上下文(其實就是一些寄存器的內容,比如指令寄存器EIP)到線程的堆棧上,記錄自己從哪里來的,等到從內核返回時,再從堆棧上加載這些信息,回到原來的地方繼續(xù)執(zhí)行。

前面提到,子進程是通過sys_execve系統(tǒng)調用進入到內核中的,在后面完成可執(zhí)行文件的分析后,拿到了ELF文件的入口地址,將會去修改原來保存在堆棧上的上下文信息,將EIP指向ELF文件的入口地址。這樣等sys_execve系統(tǒng)調用結束時,返回到用戶空間后,就能夠直接轉到新的程序入口開始執(zhí)行代碼。

所以,一個非常重要的特點是:exec系列函數(shù)正常情況下是不會返回的,一旦進入,完成使命后,執(zhí)行流程就會轉向新的可執(zhí)行文件入口。

另外需要提一下的是,在Linux上,除了ELF文件,還支持一些其他格式的可執(zhí)行文件,如MS-DOS、COFF

除了二進制的可執(zhí)行文件,還支持shell腳本,這個情況下將會將腳本解釋器程序作為入口來啟動

從ELF入口到main函數(shù)

上面交代了,一個新的進程,是如何執(zhí)行到可執(zhí)行文件的入口地址的。

同時也留了一個問題,這個入口地址是什么?是我們的main函數(shù)嗎?

這里有一個簡單的C程序,運行起來后輸出經典的hello world:

#include intmain(){ printf("hello,world! "); return0; }

通過gcc編譯后,生成了一個ELF可執(zhí)行文件,通過readelf指令,可以實現(xiàn)對ELF文件的分析,這里可以看到ELF文件的入口地址是0x400430:

隨后,我們通過反匯編神器,IDA打開分析這個文件,看一下位于0x400430入口的地方是什么函數(shù)?

可以看到,入口地方是一個叫做_start的函數(shù),并不是我們的main函數(shù)。

在_start的結尾,調用了__libc_start_main函數(shù),而這個函數(shù),位于libc.so中。

你可能疑惑,這個函數(shù)是哪里冒出來的,我們的代碼中并沒有用到它呢?

其實,在進入main函數(shù)之前,還有一個重要的工作要做,這就是:C/C++運行時庫的初始化。上面的__libc_start_main就是在完成這一工作。

在通過GCC進行編譯時,編譯器將自動完成運行時庫的鏈接,將我們的main函數(shù)封裝起來,由它來調用。

glibc是開源的,我們可以在GitHub上找到這個項目的libc-start.c文件,一窺__libc_start_main的真面目,我們的main函數(shù)正是被它在調用。

完整流程

到這里,我們梳理了,從進程創(chuàng)建fork,到通過exec系列函數(shù)完成可執(zhí)行文件的替換,再到執(zhí)行流程進入到ELF文件的入口,再到我們的main函數(shù)的完整流程。

Windows上的一些區(qū)別

下面簡單介紹下Windows上這一流程的一些差異。

首先是創(chuàng)建進程的環(huán)節(jié),Windows系統(tǒng)將fork+exec兩步合并了一步,通過CreateProcess系列函數(shù)一步到位,在其參數(shù)中指定子進程的可執(zhí)行文件路徑。

不同于Linux上進程和線程的邊界模糊,在Windows操作系統(tǒng)上,內核是有明確的進程和線程概念定義,進程用EPROCESS結構表示,線程用ETHREAD結構表示。

所以在Windows上,進程相關的工作準備就緒后,還需要單獨創(chuàng)建一個參與內核調度的執(zhí)行單元,也就是進程中的第一個線程:主線程。當然,這個工作也封裝在了CreateProcess系列函數(shù)中了。

新進程的主線程創(chuàng)建完成后,便開始參與系統(tǒng)調度了。主線程從哪里開始執(zhí)行呢?內核在創(chuàng)建時就明確進行了指定:nt!KiThreadStartup,這是一個內核函數(shù),線程啟動后就從這里開始執(zhí)行。

線程從這里啟動后,再通過Windows的異步過程調用APC機制執(zhí)行提前插入的APC,進而將執(zhí)行流程引入應用層,去執(zhí)行Windows進程應用程序的初始化工作,比如一些核心DLL文件的加載(Kernel32.dll、ntdll.dll)等等。

隨后,再次通過APC機制,再轉向去執(zhí)行可執(zhí)行文件的入口點。

這后面和Linux上的機制類似,同樣沒有直接到main函數(shù),而是需要先進行C/C++運行時庫的初始化,這之后經過運行時函數(shù)的包裝,才最終來到我們的main函數(shù)。

下面是Windows上,從創(chuàng)建進程到我們的main函數(shù)的完整流程(高清大圖:https://bbs.pediy.com/upload/attach/201604/501306_qz5f5hi1n3107kt.png):

現(xiàn)在你清楚,從進程啟動是怎么一步步到你的main函數(shù)的了嗎?

責任編輯:xj

原文標題:從創(chuàng)建進程到進入main函數(shù),發(fā)生了什么?

文章出處:【微信公眾號:strongerHuang】歡迎添加關注!文章轉載請注明出處。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • WINDOWS
    +關注

    關注

    4

    文章

    3707

    瀏覽量

    94353
  • C語言
    +關注

    關注

    183

    文章

    7646

    瀏覽量

    146205
  • 函數(shù)
    +關注

    關注

    3

    文章

    4422

    瀏覽量

    67878
  • main
    +關注

    關注

    0

    文章

    38

    瀏覽量

    6639

原文標題:從創(chuàng)建進程到進入main函數(shù),發(fā)生了什么?

文章出處:【微信號:strongerHuang,微信公眾號:strongerHuang】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    如何進一步SPI NOR閃存啟動電路板?

    穩(wěn)定性。 根據(jù) T2080 快速入門指南文檔,DIP 設置設置為 JTAG 的硬編碼 RCW,并且能夠使用 CCS 讀取硬編碼的 RCW 值。 如何進一步 SPI NOR 閃存啟動電路板
    發(fā)表于 04-16 08:51

    T型槽試驗地軌的“逆襲”:“彎了”“比新還穩(wěn)”只差這一步

    一步:先給地軌做“體檢”,判斷變形程度 動手前,必和須用專業(yè)工具摸清變形情況。如果自己判斷不準,建議直接聯(lián)系專業(yè)廠家或檢修團隊上門檢測。 輕度變形:平面度誤差≤ 0.08 mm/m。 中度變形:平面
    發(fā)表于 04-11 11:36

    光耦工作原理圖解:電→光→電,一步一步講明白

    。 ? ? ? ?很多人覺得光耦原理很復雜,其實它的工作邏輯極其簡單,核心就三:電信號轉化為光信號→光信號傳播→光信號再轉化為電信號,也就是“電→光→電”的單向傳遞過程。今天就用圖解的方式,一步一步把光耦工作原理拆透,零基礎也
    的頭像 發(fā)表于 04-03 10:29 ?459次閱讀
    光耦工作原理圖解:電→光→電,<b class='flag-5'>一步</b><b class='flag-5'>一步</b>講明白

    土體位移計安裝全攻略:組裝到埋設,一步步教你操作

    在工程安全監(jiān)測領域,土體位移計的準確安裝是保障數(shù)據(jù)可靠性的基礎。規(guī)范的安裝流程不僅能確保儀器長期穩(wěn)定運行,更能有效反映土體真實的變形情況。本文將系統(tǒng)介紹組裝到埋設的完整操作步驟,為現(xiàn)場施工提供清晰
    的頭像 發(fā)表于 03-27 15:04 ?156次閱讀
    土體位移計安裝全攻略:<b class='flag-5'>從</b>組裝到埋設,<b class='flag-5'>一步步</b>教你操作

    電表走很快,怎么回事?手把手教你排查

    先從自己家排查,再一步步向供電局或相關部門求助,做到有理有據(jù)。
    的頭像 發(fā)表于 01-19 11:28 ?1993次閱讀

    虹科答疑 | 如何將數(shù)字模擬信號映射到CAN/CAN FD報文?一步到位指南!

    ,我們結合虹科數(shù)采模塊方案,原理到實操一步步拆解映射邏輯,既講清楚底層原理,又給出可直接落地的操作步驟,幫你輕松上手!01.數(shù)采模塊到底有什么用?要實現(xiàn)物理信號
    的頭像 發(fā)表于 01-15 17:03 ?2216次閱讀
    虹科答疑 | 如何將數(shù)字模擬信號映射到CAN/CAN FD報文?<b class='flag-5'>一步</b>到位指南!

    迅為RK3588開發(fā)環(huán)境搭建“三曲”,輕松上手!

    迅為RK3588開發(fā)環(huán)境搭建“三曲”,輕松上手!
    的頭像 發(fā)表于 12-01 11:51 ?1358次閱讀
    迅為RK3588開發(fā)環(huán)境搭建“三<b class='flag-5'>步</b>曲”,<b class='flag-5'>從</b>零<b class='flag-5'>到</b><b class='flag-5'>一</b>輕松上手!

    矢量字庫實操指南:零基礎高手進階全解析!

    的全流程,帶你一步步跨越入門門檻,最終實現(xiàn)對矢量字庫的靈活運用,完成“會用”“精通”的進階。 、演示功能概述 ? AirFONT_1000 是 SPI 接口支持 16-192 矢
    的頭像 發(fā)表于 11-24 13:15 ?1647次閱讀
    矢量字庫實操指南:<b class='flag-5'>從</b>零基礎<b class='flag-5'>到</b>高手進階全解析!

    一步步完成安路飛龍 DR1M90 Linux 系統(tǒng)固化:啟動卡制作 + eMMC 固化

    本手冊由創(chuàng)龍科技研發(fā),針對安路飛龍 DR1M90,詳述 Linux 系統(tǒng)啟動卡制作(含工具包使用、PV 工具安裝等)與 eMMC 固化步驟,說明啟動卡和 eMMC 分區(qū)結構,提供 eMMC 剩余空間
    的頭像 發(fā)表于 11-21 10:48 ?6237次閱讀
    <b class='flag-5'>一步步</b>完成安路飛龍 DR1M90 Linux 系統(tǒng)固化:<b class='flag-5'>啟動</b>卡制作 + eMMC 固化

    “UPS不間斷電源罷工不開機?三專業(yè)排查,市電電池維修全解析!”

    服務器宕機、業(yè)務中斷——當UPS電源突然罷工不開機,每秒都在吞噬企業(yè)的金錢與信譽。別慌,這篇指南將帶你市電主板,一步步排查故障根源,讓設備快速恢復運行。
    的頭像 發(fā)表于 10-15 15:16 ?2266次閱讀
    “UPS不間斷電源罷工不開機?三<b class='flag-5'>步</b>專業(yè)排查,<b class='flag-5'>從</b>市電<b class='flag-5'>到</b>電池維修全解析!”

    12 個關鍵節(jié)點!文看懂 PCBA 如何實現(xiàn)零缺陷

    想知道 PCBA 加工怎么保證質量零缺陷?關鍵在 12 個核心管控節(jié)點,一步步看:?
    的頭像 發(fā)表于 09-15 15:14 ?1104次閱讀
    12 個關鍵節(jié)點!<b class='flag-5'>一</b>文看懂 PCBA 如何實現(xiàn)零缺陷

    一步步教你正確的電磁流量計安裝

    看似微小的失誤,卻會直接導致系統(tǒng)運行異常。今天簡單出期電磁流量計安裝“避坑”指南,幫你根源避開這些坑。 首先了解下電磁流量計,電磁流量計是應用法拉第電磁感應定律,根據(jù)導電流體通過外夾磁場時感生的電動勢來
    的頭像 發(fā)表于 09-06 10:38 ?4436次閱讀
    <b class='flag-5'>一步步</b>教你正確的電磁流量計安裝

    淘寶API實時競品監(jiān)控,市場策略快人一步!

    在當今激烈的電商競爭中,實時掌握競品動態(tài)是企業(yè)制勝的關鍵。淘寶作為中國最大的電商平臺,其開放API為商家提供了強大的工具,幫助實現(xiàn)實時競品監(jiān)控,從而優(yōu)化市場策略,搶占先機。本文將一步步解析如何利用
    的頭像 發(fā)表于 08-06 14:38 ?941次閱讀

    各位大佬,想問下為什么這個程序一步一步運行就可以讀出正確的讀數(shù),正常運行卻讀不出正確讀數(shù)

    各位大佬,想問下為什么這個程序一步一步運行就可以讀出正確的讀數(shù),正常運行卻讀不出正確讀數(shù)
    發(fā)表于 06-23 09:57

    智駕安全,發(fā)展一步了?

    智駕安全,發(fā)展一步了?
    的頭像 發(fā)表于 06-10 11:28 ?859次閱讀
    丹寨县| 大名县| 呼伦贝尔市| 偏关县| 郎溪县| 舟山市| 吴堡县| 沐川县| 治县。| 卓尼县| 罗定市| 昭觉县| 方山县| 时尚| 威海市| 堆龙德庆县| 广宁县| 蛟河市| 壶关县| 赤峰市| 尼勒克县| 昭平县| 漯河市| 甘南县| 平利县| 卫辉市| 银川市| 阿尔山市| 青龙| 盐山县| 巴南区| 五莲县| 大新县| 巫山县| 铜梁县| 诸城市| 建昌县| 沾益县| 宁德市| 贵州省| 台安县|