c語言程式經過編譯後,每條指令都有乙個記憶體位址,那兩個程式如果有相同記憶體位址的指令怎麼辦

時間 2021-05-11 23:22:14

1樓:Davis Wang

最終的可執行檔案中的所有符號不會有重疊,因linker會在鏈結階段做符號重定位,不會出現兩個symbol擺在同乙個位置的情況

2樓:JennyVenus

彙編指令的call,jmp,大部分都是用相對位址。

所以你會看到有著注釋裡寫著萬惡的鬼子不許我們用長轉跳,但是人民群眾的創造力是無窮的。

3樓:大妖精

4樓:愛吃土豆的橙子

這些都是基址,然後還要加上偏移量才是真的

這和CTF中pwn逆向二進位制很相似,比如棧溢位,就是要找乙個基址+offset

5樓:Jiau

程式被編譯之後會被鏈結到某個特定的位址上,然後放到Flash中儲存,當執行時會載入到記憶體中,而載入到物理記憶體的那個位址是由linux核心分配的,但是無論載入到什麼實體地址,linux核心都會把這段位址通過MMU對映到這段程式的鏈結位址上,這樣CPU在發出虛擬位址時,通過MMU就可以正確的訪問到存放程式的物理記憶體位址上的內容。

現在回到你的「兩個程式有相同的記憶體位址」的問題,如果這裡的「兩個程式」指的是兩個可執行檔案,那麼在執行時,它們會被載入到不同的實體地址上,但是會對映到相同的虛擬位址上,這其中的奧秘都來自MMU的虛擬位址到實體地址的轉換,所以不會產生你所說的相互覆蓋的問題,記憶體分配是由linux核心來完成的,核心不可能會覆蓋沒有釋放的記憶體,並且每個程式都會有自己的頁表對映,相互之間並不可見,所以你所擔心的問題也不會存在;

這裡擴充套件一種更加極端的操作,乙個程式你執行多次,你可以把多次執行看成是多個完全一樣的程式,毫無疑問,多次執行它們也不會產生任何問題,這裡每個程序又會通過頁表對映訪問相同的實體地址(忽略變數等)。

如果想要更深入的理解這些機制,可以深入研究一下MMU相關的知識。

6樓:一跟小草

OK,已經有大佬說得很清楚了。我簡單說一下自己的理解。假如你是那個程式,你看到的不同程式記憶體位址都是一樣的,這是作業系統給你的錯覺,讓你認為自己獨佔了整個位址空間和整個CPU。

這就涉及程序的概念,你可以理解為程式就是程序,程序是資源持有者,作業系統給每個程序分配空間。不同程序分配的資源不同,對應在記憶體的位置就不同,但執行時,我只需要設好每個程序的起始位址(使用者棧頂),後面都是相對這個位址的偏移。虛擬記憶體開啟後,只不過把這些位址都換成了虛擬位址,CPU硬體使用mmu自動將虛擬位址變成實體地址。

7樓:薯泥

先了解一下MMU,好多程序輪流執行在單處理器系統中,CPU 發出的指令從0x0開始,MMU 設定每個程式的能對映到的記憶體位址,這個設定是在執行這個程序之前所以MMU 保證了不同程序不會衝突

8樓:Ivan

讀了好久才讀懂題主的問題,我想大概是這樣的,不帶作業系統,裸機上只能跑乙個程式,也就是不會存在所謂的兩個程式。

而帶作業系統的,程序與程序之間是隔離的,不同的程式有不同的儲存空間。

9樓:

為了讓程式可以多個載入有很多種方式

1 相對路徑 , 有些指令是相對路徑,編譯器也會盡量能讓一些動態鏈結庫能使用相對路徑,哪怕相對值一樣,因為絕對值不一樣訪問的是不一樣的東西.

2 分層,保護模式分段分頁的話,每個程序訪問的都是邏輯位址,和實體地址關係不大.

10樓:瘋之任性

應用程式之間當然不會被相互影響,這是因為現代作業系統通過分頁實現了虛擬記憶體機制。你從objdump出來的位址都是虛擬位址,已經在鏈結過程確定了的(位址隨機化和動態鏈結除外)。在應用程式被載入時,核心存會找到空閒的實體地址去對映程序的虛擬位址,所以應用程式之間雖然虛擬位址可能相同,但是實體地址絕對不會發生衝突。

從這裡An Abstract Model of Virtual Memory盜了張圖,來說明情況:

11樓:蔣甬杭

不會互相干擾。

程序有記憶體隔離,你除錯時看到的記憶體位址是虛擬記憶體位址,並不是物理記憶體位址。

不同程序各自看到的相同的記憶體位址,在作業系統看來是不同的記憶體位址。

12樓:葉大亨

作業系統裡面會講的清楚。

程式位址是虛擬的,每個人都看似獨佔。

實際上cisc指令集裡面這麼多定址方式就是為這種實況服務的

13樓:心宇

前面一些同行已經說了,我再補充一點。

首先我們的普通程式是執行在保護模式R3下的,R3下的記憶體叫著虛擬記憶體,也就是說相對於R3下的程式每個程式都可以看到乙個完整物理記憶體大小的空間並且可以使用,程式A與程B的虛擬記憶體是隔離的。假設你的記憶體是4G,那個對於這兩個程式來說他們分別看到了自己有份完整的4G空間。那麼這不矛盾嗎?

為啥記憶體會比實際物理記憶體多?這就是虛擬記憶體,虛擬記憶體是有R0核心程式對映出來的,它有對應的物理記憶體,程式A與程式B的0x400000,對應的物理記憶體位址位址完全不同,另外它們只是看到自己有那麼大空間,實際上不是每個程式都能完整使用完所有的記憶體一旦超過上限電腦就要卡死了。

下面再說下實模式下核心程式,在這裡也是有程式執行的,除了作業系統自身就是驅動程式了,這裡的記憶體確實是位址是唯一的,不存在多個程式的指令在同一位址的現象,但如果你使用objdump 反彙編兩個核心程式,你可能還是會發現兩個程式有相同的位址。這是因為objdump是個靜態分析工具。程式在編譯期間無法確定每條指令被載入到什麼位置,因此可執行檔案(windows 下的PE格式就是exe dll這些,linux下是elf格式)定義了程式如何執行,程式沒執行前的位址是個相對位址,相對誰呢?

當然是相對基址,這個基址會編譯到可執行檔案,作業系統會預先把程式載入到此位址處。若此位址已被使用怎麼辦?這時就要提到可執行檔案的乙個區段,可執行檔案定義了指令在什麼區段,資源在什麼區段等,這其中有個最重要的區段就是重定位區段,也叫重定位表。

若基址已被占用,作業系統就會根據記憶體管理器分配出乙個新的可用的位址作為基址,然後讀取重定位表,把需要重定位的指令位址進行修正。如果你直接使用偵錯程式除錯核心這時程式是動態執行的,你會發現不會有相同程式的指令出現在同一位址的情況。

14樓:James Liu

所以為什麼要有作業系統和保護模式啊,這是個好東西。

在早期的MS-DOS或裸機中,確實可能。因為當時的CPU是實模式,因此每一條指令都會載入到乙個永遠固定的位址。但是MS-DOS是單程序作業系統啊,所以在同一時間都只會有乙個程式在執行。

但是到了後來的32位之後,情況變了。多程序已經誕生且需求廣泛,因此想出了保護模式。在保護模式下,所有的記憶體位址會被作業系統分段,成為乙個個分段後的虛擬位址。

因此每乙個程式會在每乙個虛擬記憶體空間之中進行,不會衝突。

15樓:泥偶

這是CPU體系結構、作業系統和編譯器的實現細節,跟C語言本身關係不大。

在不同的CPU體系結構、作業系統和編譯器實現上,結果可能各有不同。

16樓:庫丘林

通過反彙編得到的位址是虛擬位址,而實際載入記憶體資料需要轉化為實體地址。

首先程式會自行分段,會將指令、常量、堆疊劃分到不同的區間,這樣作業系統在分配記憶體空間時也會進行分段,也就是乙個程式所使用的記憶體不會是一段連續的空間。

其次作業系統還會進行分頁,因為每一段的資料都不是佔滿本段的,可以建立虛擬的頁和實際的記憶體幀的對應關係,需要多少頁的虛擬位址就分配多少幀的物理記憶體,不夠用的時候再分配就行。

使用虛擬記憶體的乙個好處是阻止程序對記憶體的直接訪問,避免影響其他程序的空間。另乙個好處是可以用一定磁碟空間作為虛擬空間的一部分,儲存記憶體中暫不使用的資料。但是資料在磁碟和記憶體間的換入換出比較影響效能

17樓:kevin

你說的是裸機,確實會有這種情況。

但是進入作業系統之後,你的程式看到的記憶體全是假的,甚至有可能對應的位址根本就不在記憶體,而是在硬碟上。

因為作業系統會為每個程序虛擬出記憶體,讓每個程序都覺得整個系統中只有自己乙個程式在執行。

18樓:蹦蹦騎士

這裡涉及到兩個部分的知識。

一是程序之間的記憶體是相互隔離的,採用的是虛擬位址空間的這套技術,這是cpu支援的。

現在的編譯器在編譯的時候一般都會盡可能採用相對定址,這樣可以盡可能保證位址無關。

如何用 c 語言寫乙個扔色子的程式?

GsyPs 既然問題描述要求各面的值。1 隨機朝向天的點數 2 水平方向選擇一點為參考,隨機0到360度隨機一下角度,即可確定剩下四面的朝向。3 printf 列印出來 偏扁豆 想了乙個真隨機 建乙個rpc伺服器,server端弄個worker池,每個worker負責聯絡乙個知乎的閒人負責現實中擲色...

只會c語言語法,就能強行做乙個編譯器出來嗎?

阿拉開燈 不是,會和能,是兩碼事,會是能力,能是真正去做成功!就算你把別人回答的這些東西都會了,你還是不能做出來乙個編譯器!你覺得世界上會做乙個編譯器出來的人少麼? 圓朗 在parser部分直接用現成的parser generator就好,因此編譯器前端稍微過一下就好。AST以及symbol tab...

C語言編譯器是如何實現指標 1這樣的乙個機制?

p的值被load到某個暫存器r,然後add r,4 就可以了。這裡4已經被編譯器用sizeof array item type 給換成立即數了。所以你說的什麼p 和 1,實際上沒什麼區別。如果有人要拿這個來說快慢,恕我直言,也許是因為他還不夠了解底層的cpu是如何執行指令的這乙個層面。 這個很簡單,...