ตัวชี้ฐานและตัวชี้สแต็คคืออะไร? พวกเขาทำในสิ่งที่ชี้?


225

การใช้ตัวอย่างนี้มาจากวิกิพีเดียซึ่ง DrawSquare () เรียก DrawLine ()

ข้อความแสดงแทน

(โปรดทราบว่าแผนภาพนี้มีที่อยู่สูงที่ด้านล่างและที่อยู่ต่ำที่ด้านบน)

ใครสามารถอธิบายฉันว่าอะไรebpและespอยู่ในบริบทนี้บ้าง

จากสิ่งที่ฉันเห็นฉันจะบอกว่าตัวชี้สแต็คชี้ไปที่ด้านบนสุดของสแต็กเสมอและตัวชี้พื้นฐานไปยังจุดเริ่มต้นของฟังก์ชันปัจจุบันหรือไม่ หรืออะไร?


แก้ไข: ฉันหมายถึงสิ่งนี้ในบริบทของโปรแกรม windows

edit2: และมันeipทำงานอย่างไรเช่นกัน?

edit3:ฉันมีรหัสต่อไปนี้จาก MSVC ++:

var_C= dword ptr -0Ch
var_8= dword ptr -8
var_4= dword ptr -4
hInstance= dword ptr  8
hPrevInstance= dword ptr  0Ch
lpCmdLine= dword ptr  10h
nShowCmd= dword ptr  14h

พวกเขาทั้งหมดดูเหมือนจะเป็น dwords ดังนั้นจึงใช้เวลา 4 ไบต์ต่อครั้ง ดังนั้นฉันจะเห็นว่ามีช่องว่างจาก hInstance ถึง var_4 จาก 4 ไบต์ พวกเขาคืออะไร ฉันคิดว่ามันเป็นที่อยู่ผู้ส่งคืนตามที่เห็นในรูปภาพของวิกิพีเดีย


(หมายเหตุบรรณาธิการ: ลบคำพูดยาว ๆ ออกจากคำตอบของ Michael ซึ่งไม่ได้อยู่ในคำถาม แต่มีการแก้ไขคำถามติดตาม):

นี่เป็นเพราะการไหลของการเรียกใช้ฟังก์ชันคือ:

* Push parameters (hInstance, etc.)
* Call function, which pushes return address
* Push ebp
* Allocate space for locals

คำถามของฉัน (สุดท้ายฉันหวังว่า!) ตอนนี้คือสิ่งที่เกิดขึ้นจากทันทีที่ฉันปรากฏข้อโต้แย้งของฟังก์ชั่นที่ฉันต้องการเรียกจนถึงจุดสิ้นสุดของการเปิดฉาก? ฉันต้องการที่จะรู้ว่า ebp, esp วิวัฒนาการในช่วงเวลาเหล่านั้น (ฉันได้เข้าใจแล้วว่าการทำงานของอารัมภบททำงานอย่างไรฉันแค่อยากจะรู้ว่าเกิดอะไรขึ้นหลังจากที่ฉันผลักข้อโต้แย้งไปที่กองซ้อน


23
สิ่งหนึ่งที่สำคัญที่ควรทราบคือสแต็กจะเพิ่มขึ้น "ลง" ในหน่วยความจำ ซึ่งหมายความว่าเมื่อต้องการย้ายตัวชี้สแต็กขึ้นคุณจะลดค่าของมัน
BS

4
สิ่งหนึ่งที่บ่งบอกความแตกต่างของ EBP / ESP และ EIP คือ: EBP & ESP จัดการกับข้อมูลในขณะที่ EIP เกี่ยวข้องกับรหัส
mmmmmmmm

2
ในกราฟของคุณ ebp (ปกติ) คือ "ตัวชี้เฟรม" โดยใช้ "ตัวชี้สแต็ก" สิ่งนี้ช่วยให้สามารถเข้าถึงไอเดียผ่าน [ebp-x] และพารามิเตอร์สแต็กผ่าน [ebp + x] อย่างสม่ำเสมอโดยไม่ขึ้นกับตัวชี้สแต็ก (ซึ่งมักเปลี่ยนแปลงภายในฟังก์ชัน) ที่อยู่สามารถทำได้ผ่าน ESP, การเพิ่ม EBP สำหรับการดำเนินการอื่น - แต่ด้วยวิธีนี้ผู้ debuggers ไม่สามารถบอก call stack หรือค่าของ locals
peterchen

4
@ Ben ไม่งี่เง่า คอมไพเลอร์บางตัวใส่สแต็กเฟรมเข้าในกอง แนวคิดของการเติบโตของสแต็คคือแนวคิดที่ทำให้เข้าใจง่าย การดำเนินการของสแต็กสามารถเป็นอะไรก็ได้ (การใช้ชิ้นส่วนแบบสุ่มของกองทำให้แฮ็กที่เขียนทับส่วนต่าง ๆ ของสแต็กได้ยากขึ้นมากเนื่องจากไม่ได้กำหนดไว้อย่างแน่นอน)
Martin York

1
ในสองคำ: ตัวชี้สแต็คอนุญาตให้การดำเนินการพุช / ป๊อปทำงาน (ดังนั้นพุชและป๊อปจะรู้ว่าจะใส่ / รับข้อมูล) ตัวชี้ฐานช่วยให้รหัสอ้างอิงข้อมูลที่ถูกผลักก่อนหน้านี้ในกองซ้อน
tigrou

คำตอบ:


228

esp เป็นอย่างที่คุณบอกว่ามันคือด้านบนของสแต็ค

ebpมักจะตั้งค่าให้espที่จุดเริ่มต้นของฟังก์ชั่น ebpพารามิเตอร์ฟังก์ชั่นและตัวแปรท้องถิ่นมีการเข้าถึงโดยบวกและลบตามลำดับคงชดเชยจาก อนุสัญญาการเรียก x86 ทั้งหมดกำหนดebpว่าถูกสงวนไว้ระหว่างการเรียกใช้ฟังก์ชัน ebpตัวจริงชี้ไปที่ตัวชี้ฐานของเฟรมก่อนหน้าซึ่งช่วยให้การเดินสแต็กในดีบักเกอร์และดูตัวแปรท้องถิ่นเฟรมอื่น ๆ ในการทำงาน

prologs ของฟังก์ชันส่วนใหญ่จะมีลักษณะดังนี้:

push ebp      ; Preserve current frame pointer
mov ebp, esp  ; Create new frame pointer pointing to current stack top
sub esp, 20   ; allocate 20 bytes worth of locals on stack.

จากนั้นในภายหลังในฟังก์ชั่นคุณอาจมีรหัสเช่น (สมมติว่าตัวแปรท้องถิ่นทั้งสองมี 4 ไบต์)

mov [ebp-4], eax    ; Store eax in first local
mov ebx, [ebp - 8]  ; Load ebx from second local

FPO หรือการเพิ่มประสิทธิภาพการละเว้นตัวชี้เฟรมซึ่งคุณสามารถเปิดใช้งานได้จริงจะกำจัดสิ่งนี้และใช้ebpเป็นการลงทะเบียนและเข้าถึงคนในพื้นที่โดยตรงespแต่สิ่งนี้ทำให้การดีบักยากขึ้นเล็กน้อยเนื่องจากดีบักเกอร์ไม่สามารถเข้าถึงเฟรมสแต็กของการเรียกฟังก์ชันก่อนหน้านี้

แก้ไข:

สำหรับคำถามที่อัปเดตของคุณรายการที่ขาดหายไปสองรายการในสแต็กคือ:

var_C = dword ptr -0Ch
var_8 = dword ptr -8
var_4 = dword ptr -4
*savedFramePointer = dword ptr 0*
*return address = dword ptr 4*
hInstance = dword ptr  8h
PrevInstance = dword ptr  0C
hlpCmdLine = dword ptr  10h
nShowCmd = dword ptr  14h

นี่เป็นเพราะการไหลของการเรียกใช้ฟังก์ชันคือ:

  • พารามิเตอร์ Push ( hInstanceฯลฯ )
  • ฟังก์ชั่นการโทรซึ่งจะผลักดันที่อยู่ผู้ส่ง
  • ดัน ebp
  • จัดสรรพื้นที่สำหรับคนในท้องถิ่น

1
ขอบคุณสำหรับคำอธิบาย! แต่ตอนนี้ฉันค่อนข้างสับสน สมมติว่าฉันเรียกฟังก์ชั่นและฉันอยู่ในบรรทัดแรกของการเปิดฉาก แต่ก็ยังไม่ได้ดำเนินการบรรทัดเดียวจากมัน ณ จุดนั้นคุณค่าของ ebp คืออะไร? สแต็กมีอะไรที่จุดนั้นนอกเหนือจากอาร์กิวเมนต์ที่ถูกผลักหรือไม่? ขอบคุณ!
กิน elysium

3
EBP ไม่เปลี่ยนแปลงอย่างน่าอัศจรรย์ดังนั้นจนกว่าคุณจะได้สร้าง EBP ใหม่สำหรับฟังก์ชั่นของคุณคุณจะยังคงมีค่าของผู้โทร และนอกเหนือจากข้อโต้แย้งสแต็กจะถือ EIP เก่า (ที่อยู่ผู้ส่ง) ด้วย
MSalters

3
คำตอบที่ดี แม้ว่ามันจะไม่สมบูรณ์โดยไม่ต้องพูดถึงสิ่งที่อยู่ใน epilog: "ออก" และคำแนะนำ "ret"
Calmarius

2
ฉันคิดว่าภาพนี้จะช่วยชี้แจงบางอย่างเกี่ยวกับสิ่งที่ไหล นอกจากนี้โปรดทราบว่าสแต็กจะเพิ่มขึ้นลง ocw.cs.pub.ro/courses/_media/so/laboratoare/call_stack.png
Andrei-Niculae Petre

เป็นฉันหรือเครื่องหมายลบทั้งหมดหายไปจากข้อมูลโค้ดด้านบนหรือไม่
BarbaraKwarc

96

ESP คือตัวชี้สแต็กปัจจุบันซึ่งจะเปลี่ยนแปลงเมื่อใดก็ตามที่คำหรือที่อยู่ถูกผลักหรือผุดขึ้น / ปิดออกจากสแต็ก EBP เป็นวิธีที่สะดวกกว่าสำหรับคอมไพเลอร์ในการติดตามพารามิเตอร์ของฟังก์ชั่นและตัวแปรท้องถิ่นมากกว่าการใช้ ESP โดยตรง

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

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

เมื่อออกฟังก์ชันทั้งหมดที่ต้องทำคือตั้งค่า ESP ให้เป็นค่า EBP (ซึ่งยกเลิกการจัดสรรตัวแปรท้องถิ่นจากสแต็กและแสดงรายการ EBP ที่ด้านบนสุดของสแต็ก) จากนั้นแสดงค่า EBP เก่าจากสแต็ก จากนั้นฟังก์ชันจะคืนค่า (popping ที่อยู่ผู้ส่งคืนลงใน EIP)

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


15

คุณมีสิทธิ์ ตัวชี้สแต็กชี้ไปที่รายการด้านบนของสแต็กและตัวชี้ฐานชี้ไปที่ด้านบน "ก่อนหน้า" ของสแต็กก่อนที่จะเรียกใช้ฟังก์ชัน

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

ทำจัดสรรหน่วยความจำด้วยวิธีนี้เป็นอย่างมาก , มากได้อย่างรวดเร็วและมีประสิทธิภาพ


14
@Robert: เมื่อคุณพูดว่า "ก่อนหน้า" ด้านบนของสแต็กก่อนที่จะเรียกใช้ฟังก์ชั่นคุณจะละเว้นพารามิเตอร์ทั้งสองซึ่งจะถูกผลักลงบนสแต็กก่อนที่จะเรียกฟังก์ชั่นและโทร EIP นี่อาจทำให้ผู้อ่านสับสน สมมติว่าในกรอบสแต็คมาตรฐาน EBP จะชี้ไปที่เดียวกับที่ ESP ชี้ไปหลังจากเข้าฟังก์ชั่น
wigy

7

แก้ไข:สำหรับคำอธิบายที่ดีกว่าให้ดูx86 การถอด / ฟังก์ชั่นและสแต็กเฟรมใน WikiBook เกี่ยวกับแอสเซมบลี x86 ฉันพยายามเพิ่มข้อมูลบางอย่างที่คุณอาจสนใจใช้ Visual Studio

การจัดเก็บผู้เรียก EBP เป็นตัวแปรโลคัลแรกเรียกว่าเฟรมสแต็กมาตรฐานและอาจใช้สำหรับการประชุมการโทรเกือบทั้งหมดบน Windows ความแตกต่างมีอยู่ไม่ว่าจะเป็นผู้โทรหรือ callee deallocates พารามิเตอร์ที่ผ่านและพารามิเตอร์ที่จะถูกส่งผ่านในการลงทะเบียน แต่สิ่งเหล่านี้เป็นมุมฉากกับปัญหากรอบสแต็คมาตรฐาน

พูดเกี่ยวกับโปรแกรม Windows คุณอาจใช้ Visual Studio เพื่อคอมไพล์รหัส C ++ ของคุณ ระวังให้ดีว่า Microsoft ใช้การปรับให้เหมาะสมที่เรียกว่า Frame Pointer Omission ซึ่งทำให้แทบเป็นไปไม่ได้เลยที่จะเดินบนสแต็กโดยไม่ต้องใช้ไลบรารี dbghlp และไฟล์ PDB สำหรับการปฏิบัติการ

Frame Pointer Omission หมายความว่าคอมไพเลอร์ไม่ได้จัดเก็บ EBP เก่าไว้ในสถานที่มาตรฐานและใช้การลงทะเบียน EBP สำหรับสิ่งอื่นดังนั้นคุณมีเวลาหา EIP ของผู้โทรได้ยากโดยไม่ทราบว่าต้องใช้ตัวแปรเฉพาะที่สำหรับฟังก์ชันที่กำหนด แน่นอนว่า Microsoft มี API ที่อนุญาตให้คุณทำ stack-walk แม้ในกรณีนี้ แต่การค้นหาฐานข้อมูลตารางสัญลักษณ์ในไฟล์ PDB นั้นใช้เวลานานเกินไปสำหรับการใช้งานบางกรณี

เพื่อหลีกเลี่ยง FPO ในหน่วยการคอมไพล์ของคุณคุณต้องหลีกเลี่ยงการใช้ / O2 หรือจำเป็นต้องเพิ่ม / Oy- ไปยังแฟล็กการคอมไพล์ C ++ ในโครงการของคุณ คุณอาจเชื่อมโยงกับ C หรือ C ++ รันไทม์ซึ่งใช้ FPO ในการกำหนดค่าการวางจำหน่ายดังนั้นคุณจะมีเวลายากที่จะทำ stack เดินโดยไม่ต้อง dbghlp.dll


ฉันไม่เข้าใจวิธีการจัดเก็บ EIP ในสแต็ก มันควรจะเป็นทะเบียนหรือไม่? การลงทะเบียนสามารถอยู่ในสแต็กได้อย่างไร? ขอบคุณ!
กิน elysium

EIP ของผู้โทรถูกส่งไปยังสแต็กโดยคำสั่ง CALL คำสั่ง RET ดึงเฉพาะส่วนบนสุดของสแต็กและวางลงใน EIP หากคุณมีบัฟเฟอร์โอเวอร์รันความจริงนี้อาจถูกใช้เพื่อข้ามไปยังรหัสผู้ใช้จากเธรดที่มีสิทธิใช้งาน
wigy

@devouredelysium เนื้อหา (หรือค่า ) ของการลงทะเบียน EIP จะถูกวาง (หรือคัดลอกไปยัง) สแต็กไม่ใช่ที่รีจิสเตอร์เอง
BarbaraKwarc

@BarbaraKwarc ขอบคุณสำหรับการป้อนค่าที่คุ้มค่า ฉันไม่สามารถเห็นสิ่งที่ OP หายไปจากคำตอบของฉัน ความจริงแล้วรีจิสเตอร์ยังคงอยู่ในที่ที่มีค่าของพวกเขาเท่านั้นที่ถูกส่งไปยัง RAM จาก CPU ในโหมด amd64 สิ่งนี้จะซับซ้อนกว่านี้เล็กน้อย แต่ปล่อยให้เป็นปัญหาอื่น
wigy

อะไรคือ amd64 ฉันอยากรู้.
BarbaraKwarc

6

ประการแรกตัวชี้สแต็กชี้ไปที่ด้านล่างของสแต็กตั้งแต่ x86 สแต็คสร้างจากค่าที่อยู่สูงไปยังค่าที่อยู่ต่ำลง ตัวชี้สแต็กเป็นจุดที่การโทรครั้งต่อไปที่จะผลักดัน (หรือโทร) จะวางค่าต่อไป การดำเนินการเทียบเท่ากับคำสั่ง C / C ++:

 // push eax
 --*esp = eax
 // pop eax
 eax = *esp++;

 // a function call, in this case, the caller must clean up the function parameters
 move eax,some value
 push eax
 call some address  // this pushes the next value of the instruction pointer onto the
                    // stack and changes the instruction pointer to "some address"
 add esp,4 // remove eax from the stack

 // a function
 push ebp // save the old stack frame
 move ebp, esp
 ... // do stuff
 pop ebp  // restore the old stack frame
 ret

ตัวชี้ฐานอยู่ด้านบนของเฟรมปัจจุบัน โดยทั่วไป ebp จะชี้ไปยังที่อยู่ผู้ส่งของคุณ ebp + 4 ชี้ไปที่พารามิเตอร์แรกของฟังก์ชั่นของคุณ (หรือค่าของวิธีการเรียน) ebp-4 ชี้ไปที่ตัวแปรท้องถิ่นตัวแรกของฟังก์ชั่นของคุณโดยปกติจะเป็นค่าเก่าของ ebp เพื่อให้คุณสามารถกู้คืนตัวชี้เฟรมก่อนหน้า


2
ไม่ ESP ไม่ได้ชี้ไปที่ด้านล่างของสแต็ก โครงร่างการกำหนดแอดเดรสหน่วยความจำไม่เกี่ยวข้องกับมัน ไม่สำคัญว่าสแต็กจะโตขึ้นหรือลดลง "ด้านบน" ของสแต็กมักจะมีการผลักดันค่าถัดไป (วางที่ด้านบนสุดของสแต็ก) หรือบนสถาปัตยกรรมอื่น ๆ ที่วางค่าการผลักครั้งล่าสุดและวางที่ปัจจุบัน ดังนั้น ESP จะชี้ไปที่ด้านบนสุดของสแต็กเสมอ
BarbaraKwarc

1
ด้านล่างหรือฐานของสแต็คในมืออื่น ๆ ที่เป็นที่แรก (หรือที่เก่าแก่ที่สุด ) มูลค่าได้รับการใส่และจากนั้นปกคลุมด้วยค่าเมื่อเร็ว ๆ นี้ นั่นคือที่ชื่อ "ตัวชี้ฐาน" สำหรับ EBP มาจาก: มันควรจะชี้ไปที่ฐาน (หรือด้านล่าง) ของสแต็คท้องถิ่นปัจจุบันของรูทีนย่อย
BarbaraKwarc

บาร์บาร่าใน Intel x86 สแต็คจะคว่ำลง ด้านบนของสแต็คมีรายการแรกที่ผลักไปยังสแต็คและแต่ละรายการหลังจากถูกผลักด้านล่างรายการด้านบน ด้านล่างของสแต็คคือตำแหน่งที่วางไอเท็มใหม่ โปรแกรมจะอยู่ในหน่วยความจำเริ่มต้นที่ 1k และเติบโตขึ้นถึงอนันต์ สแต็กเริ่มต้นที่อินฟินิตี้, mem สูงสุดลบด้วย ROM และเพิ่มขึ้นเป็น 0 ESP ชี้ไปยังที่อยู่ที่มีค่าน้อยกว่าที่อยู่แรกที่ผลัก
jmucchiello

1

นานมาแล้วที่ฉันเขียนโปรแกรม Assembly แต่ลิงค์นี้อาจมีประโยชน์ ...

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

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

การลงทะเบียนฐานหรือการลงทะเบียนเซกเมนต์เพียงชี้ไปที่พื้นที่ที่อยู่ของข้อมูลจำนวนมาก เมื่อรวมกับผู้ลงทะเบียนที่สองตัวชี้ฐานจะแบ่งหน่วยความจำในบล็อกขนาดใหญ่ในขณะที่การลงทะเบียนครั้งที่สองจะชี้ไปที่รายการภายในบล็อกนี้ ตัวชี้ฐานจึงชี้ไปที่ฐานของบล็อกของข้อมูล

โปรดทราบว่า Assembly เป็น CPU ที่เฉพาะเจาะจงมาก หน้าเว็บที่ฉันเชื่อมโยงเพื่อให้ข้อมูลเกี่ยวกับ CPU ประเภทต่าง ๆ


การลงทะเบียนเซกเมนต์แยกจากกันบน x86 - พวกมันคือ gs, cs, ss และเว้นแต่ว่าคุณกำลังเขียนซอฟต์แวร์การจัดการหน่วยความจำคุณไม่เคยแตะมันเลย
Michael

ds ยังเป็นการลงทะเบียนเซกเมนต์และในวันที่ MS-DOS และรหัส 16 บิตคุณจำเป็นต้องเปลี่ยนการลงทะเบียนเซ็กเมนต์เหล่านี้เป็นครั้งคราวเนื่องจากไม่สามารถชี้ไปที่ RAM ขนาดใหญ่กว่า 64 KB กระนั้น DOS ก็สามารถเข้าถึงหน่วยความจำได้สูงสุด 1 MB เพราะมันใช้พอยน์เตอร์แอดเดรส 20 บิต ต่อมาเรามีระบบ 32- บิตบางระบบมีการลงทะเบียนที่อยู่ 36 บิตและขณะนี้มีการลงทะเบียน 64 บิต ดังนั้นทุกวันนี้คุณไม่จำเป็นต้องเปลี่ยนการลงทะเบียนกลุ่มเหล่านี้อีกต่อไป
Wim ten Brink

ไม่มีระบบปฏิบัติการที่ทันสมัยใช้ 386 เซ็กเมนต์
Ana Betts

@ พอล: ผิด! ไม่ถูกต้อง! ไม่ถูกต้อง! เซ็กเมนต์ 16 บิตจะถูกแทนที่ด้วยเซ็กเมนต์ 32 บิต ในโหมดที่ได้รับการป้องกันสิ่งนี้จะช่วยให้การจำลองเสมือนของหน่วยความจำโดยทั่วไปทำให้โปรเซสเซอร์สามารถจับคู่ฟิสิคัลแอดเดรสกับโลจิคัล อย่างไรก็ตามในแอปพลิเคชันของคุณสิ่งต่าง ๆ ดูเหมือนจะยังคงแบนเนื่องจากระบบปฏิบัติการเสมือนหน่วยความจำสำหรับคุณ เคอร์เนลทำงานในโหมดป้องกันช่วยให้แอปพลิเคชันสามารถทำงานในรูปแบบหน่วยความจำแบบแบน ดูen.wikipedia.org/wiki/Protected_mode
Wim ten Brink

@Workshop ALex: นั่นเป็นเรื่องทางเทคนิค ระบบปฏิบัติการที่ทันสมัยทั้งหมดตั้งค่าทุกส่วนเป็น [0, FFFFFFFF] ที่ไม่นับจริง ๆ และถ้าคุณอ่านหน้าเชื่อมโยงคุณจะเห็นว่าสิ่งที่น่าสนใจทั้งหมดทำกับหน้าเว็บซึ่งมีการแบ่งส่วนละเอียดมากขึ้น
MSalters

-4

แก้ไขใช่นี่เป็นความผิดส่วนใหญ่ มันอธิบายบางสิ่งที่แตกต่างอย่างสิ้นเชิงในกรณีที่ใครสนใจ :)

ใช่ตัวชี้สแต็กชี้ไปที่ด้านบนของสแต็ก (ไม่ว่าจะเป็นตำแหน่งสแต็กแรกที่ว่างเปล่าหรือเต็มรูปแบบล่าสุดที่ฉันไม่แน่ใจ) ตัวชี้พื้นฐานชี้ไปยังตำแหน่งหน่วยความจำของคำสั่งที่กำลังดำเนินการ นี่คือระดับของ opcode - คำสั่งพื้นฐานที่สุดที่คุณสามารถหาได้ในคอมพิวเตอร์ แต่ละ opcode และพารามิเตอร์ของมันถูกเก็บไว้ในตำแหน่งหน่วยความจำ หนึ่งบรรทัด C หรือ C ++ หรือ C # สามารถแปลเป็นหนึ่ง opcode หรือลำดับของสองคนหรือมากกว่านั้นขึ้นอยู่กับความซับซ้อนของมัน สิ่งเหล่านี้ถูกเขียนลงในหน่วยความจำของโปรแกรมตามลำดับและดำเนินการ ภายใต้สถานการณ์ปกติตัวชี้พื้นฐานจะเพิ่มขึ้นหนึ่งคำสั่ง สำหรับการควบคุมโปรแกรม (GOTO, IF ฯลฯ ) สามารถเพิ่มได้หลายครั้งหรือแทนที่ด้วยที่อยู่หน่วยความจำถัดไป

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


ฉันมีปัญหาเล็กน้อยในการทำความเข้าใจว่า ebp คืออะไร ถ้าเรามีรหัส MASM 10 บรรทัดนั่นหมายความว่าเมื่อเราใช้งานบรรทัดเหล่านั้น ebp จะเพิ่มขึ้นตลอดเวลาหรือไม่
กิน elysium

1
@ Devoured - ไม่นั่นไม่ใช่ความจริง eip จะเพิ่มขึ้น
Michael

คุณหมายถึงสิ่งที่ฉันพูดถูกต้อง แต่ไม่ใช่สำหรับ EBP แต่สำหรับ IEP นั่นคือสิ่งนั้นใช่หรือไม่
กิน elysium

2
ใช่. EIP เป็นตัวชี้คำสั่งและมีการปรับเปลี่ยนโดยปริยายหลังจากดำเนินการแต่ละคำสั่ง
Michael

2
โอ้ฉันไม่ดี ฉันกำลังคิดถึงตัวชี้ที่แตกต่าง ฉันคิดว่าฉันจะไปล้างสมองของฉัน
Stephen Friederichs

-8

esp ย่อมาจาก "Extended Stack Pointer" ..... ebp สำหรับ "Something Base Pointer" .... และ eip สำหรับ "Something Instruction Pointer" ...... ตัวชี้ Stack ชี้ไปยังที่อยู่ออฟเซ็ตของส่วนสแต็ก . ตัวชี้ฐานชี้ไปยังที่อยู่ตรงข้ามของส่วนเพิ่มเติม Instruction Pointer ชี้ไปยังที่อยู่ตรงข้ามของส่วนรหัส ตอนนี้เกี่ยวกับเซกเมนต์ ... พวกเขาเป็นส่วนเล็ก ๆ 64KB ของพื้นที่หน่วยความจำโปรเซสเซอร์ ..... กระบวนการนี้เรียกว่าการแบ่งเซ็กเมนต์หน่วยความจำ ฉันหวังว่าโพสต์นี้จะเป็นประโยชน์


3
นี่เป็นคำถามเก่าอย่างไรก็ตาม sp ย่อมาจาก stack pointer, bp ย่อมาจาก base pointer และ ip สำหรับ pointer pointer จุดเริ่มต้นของทุกคนกำลังบอกว่ามันเป็นตัวชี้ 32 บิต
Hyden

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