ที่อยู่หน่วยความจำคงที่แบบคงที่ [10] จะสิ้นสุดลงใน 060 เสมอ


17

ฉันมีโปรแกรม ac ที่มีลักษณะเช่นนี้

main.c

#include <stdio.h>
#define SOME_VAR 10

static int heap[SOME_VAR];


int main(void) {
    printf("%p", heap);
    return 0;
}

และส่งออกสิ่งนี้เมื่อฉันรันโปรแกรมที่คอมไพล์แล้วสองสามครั้ง

0x58aa7c49060
0x56555644060
0x2f8d1f8e060
0x92f58280060
0x59551c53060
0xd474ed6e060
0x767c4561060
0xf515aeda060
0xbe62367e060

ทำไมมันถึงลงท้ายด้วย 060 เสมอ? และอาร์เรย์เก็บไว้ในกองหรือไม่

แก้ไข: ฉันใช้ Linux และฉันเปิด ASLR ฉันรวบรวมโปรแกรมโดยใช้ gcc


2
ระบบปฏิบัติการอะไร เรียบเรียงอะไร?
Andrew Henle

2
ตัวแปรที่ไม่ได้อยู่ในกองมันมีอยู่ในข้อมูลหรือ bss ส่วนของพื้นที่ที่อยู่ของโปรแกรมดูen.wikipedia.org/wiki/Static_variable ฉันเดาว่าโปรแกรมจะถูกวางไว้ที่ที่อยู่หน่วยความจำในขอบเขตที่แน่นอนเสมอเช่นหารด้วย 0x1000 และตัวแปรจะถูกวางโดยคอมไพเลอร์ที่ออฟเซ็ตคงที่ในพื้นที่ที่อยู่ของโปรแกรม
Bodo

คำตอบ:


15

ที่อยู่แตกต่างกันเนื่องจาก ASLR (ramdomization เค้าโครงพื้นที่ที่อยู่) การใช้สิ่งนี้ไบนารีสามารถถูกแมปในตำแหน่งที่ตั้งต่าง ๆ ในพื้นที่ที่อยู่เสมือน

ตัวแปรheapคือ - ในทางตรงกันข้ามกับชื่อของมัน - ไม่ได้อยู่ในกอง bssแต่ใน ออฟเซ็ตในพื้นที่ที่อยู่จึงคงที่

หน้าจะถูกแมปที่หน้าย่อยซึ่งเป็น 4096 ไบต์ (ฐานสิบหก: 0x1000) ในหลายแพลตฟอร์ม นี่คือเหตุผลทำไมตัวเลขฐานสิบหกสามอันสุดท้ายของที่อยู่เดียวกัน

เมื่อคุณทำเช่นเดียวกันกับตัวแปรสแต็คที่อยู่อาจแตกต่างกันไปในตัวเลขหลักสุดท้ายในบางแพลตฟอร์ม (เช่น linux กับเคอร์เนลล่าสุด) เนื่องจากสแต็กไม่ได้ถูกแมปเฉพาะที่อื่น แต่ยังได้รับออฟเซ็ตแบบสุ่มเมื่อเริ่มต้น


ASLR สุ่มฐานของการโหลดตามที่ฉันจำได้ ที่อยู่ของส่วนจะขึ้นอยู่กับที่อยู่นั้น
Afshin

ฉันใช้หนังสือเกี่ยวกับการเขียนโปรแกรมเชิงวัตถุ ANSI-C โดย Axel-Thobias Schreiner หนังสือเล่มนี้เขียนในปี 1993 คุณรู้หรือไม่ว่าเลย์เอาต์ของหน่วยความจำนั้นแตกต่างไปจากนี้หรือไม่ ถ้าไม่ใช่ทำไมเขาอาจตั้งชื่อตัวแปรheapเมื่อมันไม่ได้อยู่ในกอง?
linuxlmao

4096 แปลเป็น 060 ในบางวิธีหรือ 0x1000 แปลเป็น 060 ไม่เช่นนั้นฉันไม่เข้าใจว่าคุณหมายถึงอะไรเพราะเป็นสาเหตุของการสิ้นสุด ฉันคิดว่าอาจต้องทำอย่างไรกับขนาดของอาร์เรย์ที่เป็นสิ่งที่แปลเป็นเลขฐานสิบหกจาก 060 เช่นทศนิยม
linuxlmao

2
@linuxlmao ชดเชยเป็นตัวอย่าง 14,060 ดังนั้นเมื่อคุณเพิ่มหลายขนาดหน้า (0x1000) 060ที่ตัวเลขสามหลักสุดท้ายยังคงอยู่
Ctx

4

หากคุณใช้ Windows เหตุผลก็คือโครงสร้างPE

heapตัวแปรของคุณถูกเก็บไว้ใน.dataส่วนของไฟล์และที่อยู่ของมันจะคำนวณตามจุดเริ่มต้นของส่วนนี้ แต่ละส่วนมีการโหลดในที่อยู่อย่างอิสระ แต่ที่อยู่เริ่มต้นของมันคือหลายขนาดหน้า เนื่องจากคุณไม่มีตัวแปรอื่น ๆ ที่อยู่ของมันน่าจะเป็นจุดเริ่มต้นของ.dataส่วนดังนั้นที่อยู่ของมันจะมีหลายขนาด

ตัวอย่างเช่นนี้เป็นตารางของ Windows รุ่นที่รวบรวมของรหัสของคุณ: ส่วนจะถูกรวบรวมรหัสของคุณและมีคุณตัวแปร เมื่อ PE ของคุณถูกโหลดเข้าสู่หน่วยความจำส่วนต่างๆจะถูกโหลดในที่อยู่ที่แตกต่างกันซึ่งจะถูกส่งคืนโดยและจะมีขนาดหน้ากระดาษหลายขนาด แต่ที่อยู่ของตัวแปรแต่ละตัวนั้นสัมพันธ์กับการเริ่มต้นของส่วนที่ตอนนี้เป็นขนาดหน้ากระดาษ ดังนั้นคุณจะเห็นตัวเลขคงที่เสมอกับตัวเลขที่ต่ำกว่า เนื่องจากที่อยู่ญาติของตั้งแต่เริ่มต้นของส่วนจะขึ้นอยู่กับคอมไพเลอร์ตัวเลือกการรวบรวม ฯลฯ คุณจะเห็นจำนวนที่แตกต่างจากรหัสเดียวกัน แต่คอมไพเลอร์ที่แตกต่างกัน แต่ทุกครั้งสิ่งที่จะพิมพ์จะได้รับการแก้ไขส่วน.text.dataheapVirtualAlloc()heap

เมื่อฉันรวบรวมรหัสฉันสังเกตเห็นheapถูกวางใน0x8B0ไบต์หลังจากเริ่มต้นของ.dataส่วน 0x8B0ดังนั้นทุกครั้งที่ผมใช้รหัสนี้สิ้นสุดในที่อยู่ของฉัน


ฉันใช้หนังสือเกี่ยวกับการเขียนโปรแกรมเชิงวัตถุ ANSI-C โดย Axel-Thobias Schreiner หนังสือเล่มนี้เขียนในปี 1993 คุณรู้หรือไม่ว่าเลย์เอาต์ของหน่วยความจำนั้นแตกต่างไปจากนี้หรือไม่ ถ้าไม่ใช่ทำไมเขาอาจตั้งชื่อตัวแปรheapเมื่อมันไม่ได้อยู่ในกอง?
linuxlmao

2
@ linuxlmao มันอาจจะแตกต่างกัน ในปี 1993 Windows เป็นระบบปฏิบัติการ 16 บิตพร้อมการแบ่งเซ็กเมนต์หน่วยความจำและสิ่งต่าง ๆ ที่สร้างความสับสน มันไม่ใช่สถาปัตยกรรมหน่วยความจำแบบแบน 32 บิตเหมือนเดิม แต่สิ่งเหล่านี้เป็นสาเหตุที่การถาม / ตอบคำถามทั่วไปเกี่ยวกับเลย์เอาต์ของโปรแกรมไบนารีในหน่วยความจำนั้นไม่มีประโยชน์ ทำความเข้าใจกับสิ่งที่มาตรฐานภาษา C รับประกันให้กับคุณโดยทั่วไปและนั่นคือทั้งหมดที่คุณต้องรู้ เพียงกังวลเกี่ยวกับเค้าโครงที่เกิดขึ้นจริงหากคุณกำลังดีบักปัญหาที่เฉพาะเจาะจงจากนั้นใช้ดีบักเกอร์
Cody Gray

ไม่ไม่ควรสร้างตัวแปรบนฮีปแม้ในระบบเก่าเพราะไม่ได้รับการจัดสรรด้วย malloc และมีระยะเวลาการจัดเก็บแบบคงที่
phuclv

@Ashshin ฉันกำลังพูดถึงความคิดเห็นของ OP ข้างต้น
phuclv

@phuclv ขอโทษเพราะคุณไม่ได้พูดถึงเขาฉันคิดว่าคุณกำลังพูดกับฉัน :)
Afshin

4

คอมไพเลอร์เกิดการวางheapออฟเซ็ต 0x60 ไบต์ในเซ็กเมนต์ข้อมูลซึ่งอาจเป็นเพราะคอมไพเลอร์มีข้อมูลอื่น ๆ ใน 0x60 ไบต์แรกเช่นข้อมูลที่ใช้โดยรหัสที่เริ่มmainรูทีน นั่นคือเหตุผลที่คุณเห็น“ 060”; มันเป็นเพียงที่ที่มันเกิดขึ้นและไม่มีความสำคัญกับมัน

การสุ่มเค้าโครงพื้นที่ที่อยู่เปลี่ยนที่อยู่พื้นฐาน (es) ที่ใช้สำหรับส่วนต่าง ๆ ของหน่วยความจำของโปรแกรม แต่จะทำเช่นนั้นในหน่วย 0x1000 ไบต์ (เพราะสิ่งนี้จะทำให้เกิดปัญหากับการจัดตำแหน่งและปัญหาอื่น ๆ ) ดังนั้นคุณจะเห็นที่อยู่มีความผันผวนตามทวีคูณของ 0x1000 แต่ตัวเลขสามหลักสุดท้ายไม่เปลี่ยนแปลง

คำจำกัดความstatic int heap[SOME_VAR];กำหนดheapด้วยระยะเวลาการจัดเก็บแบบคงที่ การใช้งานทั่วไป C เก็บไว้ในส่วนข้อมูลทั่วไปไม่ได้อยู่ในกอง “ ฮีป” เป็นชื่อเรียกผิดสำหรับหน่วยความจำที่ใช้สำหรับการจัดสรรแบบไดนามิก (เป็นผู้เรียกชื่อผิดเนื่องจากmallocการใช้งานอาจใช้โครงสร้างข้อมูลและอัลกอริธึมที่หลากหลายซึ่งไม่ จำกัด เพียงฮีปพวกเขาอาจใช้หลายวิธีในการปรับใช้ครั้งเดียว)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.