อ่านเพิ่มเติมสำหรับหัวข้อใด ๆ ที่นี่: คู่มือการเรียกระบบ Linux ที่ชัดเจน
ฉันตรวจสอบสิ่งเหล่านี้โดยใช้ GNU Assembler (gas) บน Linux
ส่วนต่อประสานเคอร์เนล
x86-32 aka i386 Linux System Call Convention:
ในพารามิเตอร์ x86-32 สำหรับการเรียกระบบ Linux ถูกส่งผ่านโดยใช้รีจิสเตอร์ %eax
สำหรับ syscall_number % ebx,% ecx,% edx,% esi,% edi,% ebp ใช้สำหรับส่งพารามิเตอร์ 6 ตัวไปยังการเรียกของระบบ
%eax
ค่าตอบแทนอยู่ใน ทั้งหมดลงทะเบียนอื่น ๆ (รวมธง) int $0x80
จะถูกเก็บไว้ใน
ฉันติดตามตัวอย่างจากLinux Assembly Tutorialแต่ฉันสงสัยเกี่ยวกับสิ่งนี้ หากใครสามารถแสดงตัวอย่างมันจะดี
หากมีข้อโต้แย้งมากกว่าหกข้อ
%ebx
ต้องมีตำแหน่งหน่วยความจำที่จัดเก็บรายการข้อโต้แย้ง - แต่ไม่ต้องกังวลเกี่ยวกับสิ่งนี้เพราะมันไม่น่าเป็นไปได้ที่คุณจะใช้ syscall ที่มีข้อโต้แย้งมากกว่าหกข้อ
สำหรับตัวอย่างเล็ก ๆ น้อย ๆ และอ่านเพิ่มเติมโปรดดูที่http://www.int80h.org/bsdasm/#alternate-calling-convention อีกตัวอย่างหนึ่งของ Hello World สำหรับ i386 Linux ที่ใช้int 0x80
: Hello, world ในภาษาแอสเซมบลีด้วยการเรียกระบบ Linux?
sysenter
ใช้: มีวิธีที่เร็วกว่าการโทรระบบ 32 บิตเป็น เคอร์เนลแมปหน้าหน่วยความจำในทุกกระบวนการ (the vDSO) กับด้านผู้ใช้พื้นที่ของการsysenter
เต้นรำซึ่งจะต้องร่วมมือกับเคอร์เนลเพื่อให้สามารถค้นหาที่อยู่ผู้ส่ง int $0x80
หาเรื่องที่จะลงทะเบียนการทำแผนที่เป็นเช่นเดียวกับ ปกติแล้วคุณควรโทรเข้าสู่ vDSO แทนที่จะใช้sysenter
โดยตรง (ดูคู่มือขั้นสูงสำหรับการโทรระบบ Linuxสำหรับข้อมูลเกี่ยวกับการเชื่อมโยงและการโทรเข้าสู่ vDSO และสำหรับข้อมูลเพิ่มเติมเกี่ยวกับsysenter
และทุกสิ่งอื่นที่เกี่ยวข้องกับการโทรของระบบ)
x86-32 [ฟรี | เปิด | สุทธิ | DragonFly] การประชุมการเรียกระบบ BSD UNIX:
พารามิเตอร์ถูกส่งผ่านบนสแต็ก ผลักดันพารามิเตอร์ (พารามิเตอร์สุดท้ายผลักก่อน) ไปยังสแต็ก จากนั้นดันข้อมูลจำลอง 32 บิตเพิ่มเติม (ไม่ใช่ข้อมูลจำลองจริงอ้างถึงลิงก์ต่อไปนี้สำหรับข้อมูลเพิ่มเติม) จากนั้นให้คำแนะนำการเรียกระบบint $0x80
http://www.int80h.org/bsdasm/#default-calling-convention
x86-64 การประชุมการเรียกระบบ Linux:
x86-64 Mac OS X คล้ายกัน แต่ที่แตกต่างกัน สิ่งที่ต้องทำ: ตรวจสอบสิ่งที่ * BSD ทำ
ดูส่วน "A.2 AMD64 ลินุกซ์อนุสัญญา kernel" ของระบบวี Application Binary Interface AMD64 สถาปัตยกรรมเสริมประมวลผล รุ่นล่าสุดของ i386 และ x86-64 System V psABIs สามารถพบได้เชื่อมโยงจากหน้านี้ใน repo (ดูเพิ่มเติมที่x86 ติดแท็ก wiki สำหรับลิงก์ ABI ที่ทันสมัยและสิ่งดีๆอื่น ๆ อีกมากมายเกี่ยวกับ x86 asm)
นี่คือตัวอย่างจากส่วนนี้:
- แอปพลิเคชันระดับผู้ใช้ใช้เป็นทะเบียนจำนวนเต็มสำหรับการส่งลำดับ% rdi,% rsi,% rdx,% rcx,% r8 และ% r9 เคอร์เนลอินเตอร์เฟสใช้% rdi,% rsi,% rdx,% r10,% r8 และ% r9
- ระบบโทรจะทำผ่านการเรียนการสอน
syscall
การอุดตันนี้% rcx และ% r11รวมถึงค่าที่คืนกลับมา% rax แต่การลงทะเบียนอื่น ๆ จะถูกเก็บไว้
- จำนวน syscall ต้องถูกส่งผ่านใน register% rax
- การเรียกระบบถูก จำกัด ไว้ที่หกอาร์กิวเมนต์เท่านั้นไม่มีการส่งผ่านอาร์กิวเมนต์บนสแต็กโดยตรง
- เมื่อกลับมาจาก syscall register% rax จะมีผลลัพธ์ของการเรียกระบบ ค่าอยู่ในช่วงระหว่าง -4095 และ -1
-errno
บ่งชี้ข้อผิดพลาดก็คือ
- เฉพาะค่าของคลาส INTEGER หรือคลาส MEMORY เท่านั้นที่ถูกส่งไปยังเคอร์เนล
โปรดจำไว้ว่านี่คือจากภาคผนวกลินุกซ์ที่เฉพาะเจาะจงไปยัง ABI และสำหรับลินุกซ์มันเป็นข้อมูลที่ไม่เชิงบรรทัดฐาน (แต่จริงๆแล้วมันถูกต้อง)
int $0x80
ABI 32 บิตนี้สามารถใช้งานได้ในรหัส 64 บิต (แต่ไม่แนะนำอย่างยิ่ง) จะเกิดอะไรขึ้นถ้าคุณใช้ 32-bit int 0x80 Linux ABI ในรหัส 64- บิต มันยังตัดทอนอินพุตเป็น 32- บิตดังนั้นจึงไม่เหมาะสำหรับพอยน์เตอร์และค่าศูนย์ r8-r11
ส่วนต่อประสานผู้ใช้: การเรียกใช้ฟังก์ชัน
x86-32 การประชุมการเรียกใช้ฟังก์ชัน:
ในพารามิเตอร์ x86-32 ถูกส่งผ่านบนสแต็ก พารามิเตอร์สุดท้ายถูกผลักไปที่สแต็กเป็นอันดับแรกจนกระทั่งพารามิเตอร์ทั้งหมดเสร็จสิ้นจากนั้นcall
คำสั่งถูกเรียกใช้ ใช้สำหรับเรียกฟังก์ชัน C library (libc) บน Linux จากชุดประกอบ
เวอร์ชันล่าสุดของ i386 System V ABI (ใช้บน Linux) จำเป็นต้องมีการจัดตำแหน่งแบบ 16 ไบต์%esp
ก่อน a call
เช่น x86-64 System V ABI จำเป็นต้องมีเสมอ Callees ได้รับอนุญาตให้สันนิษฐานได้และใช้ SSE 16-byte load / stores แต่ในอดีตลินุกซ์ต้องการการจัดตำแหน่งสแต็ก 4 ไบต์เท่านั้นดังนั้นจึงต้องทำงานพิเศษเพื่อสงวนพื้นที่ที่จัดชิดตามธรรมชาติแม้กระทั่งสำหรับ 8 ไบต์double
หรือบางอย่าง
ระบบ 32 บิตสมัยใหม่อื่น ๆ บางระบบยังไม่ต้องการการจัดแนวสแต็กมากกว่า 4 ไบต์
x86-64 System V พื้นที่ผู้ใช้แบบแผน
x86-64 System V ผ่าน args ในการลงทะเบียนซึ่งมีประสิทธิภาพมากกว่าการประชุม stack args ของ i386 System V มันหลีกเลี่ยงเวลาแฝงและคำแนะนำพิเศษในการจัดเก็บ args ไปยังหน่วยความจำ (แคช) แล้วโหลดมันกลับมาอีกครั้งใน callee สิ่งนี้ใช้ได้ดีเพราะมีการลงทะเบียนมากขึ้นและดีกว่าสำหรับซีพียูประสิทธิภาพสูงรุ่นใหม่ที่มีความหน่วงแฝงและการดำเนินการที่ไม่เป็นไปตามคำสั่ง (i386 ABI นั้นเก่ามาก)
ในกลไกใหม่นี้: อันดับแรกพารามิเตอร์จะแบ่งออกเป็นคลาส คลาสของแต่ละพารามิเตอร์กำหนดลักษณะที่มันจะถูกส่งผ่านไปยังฟังก์ชั่นที่เรียกว่า
สำหรับข้อมูลที่สมบูรณ์ดูที่: "3.2 ลำดับการเรียกใช้ฟังก์ชัน" ของSystem V Application Binary Interface AMD64 Architecture Processor Supplementซึ่งอ่านส่วนหนึ่ง:
เมื่อมีการจำแนกข้อโต้แย้งการลงทะเบียนจะได้รับมอบหมาย (ตามลำดับจากซ้ายไปขวา) สำหรับการส่งผ่านดังนี้:
- ถ้าคลาสคือ MEMORY ให้ส่งอาร์กิวเมนต์ไปยังสแต็ก
- ถ้าคลาสนั้นเป็น INTEGER จะใช้การลงทะเบียนลำดับถัดไปของลำดับ% rdi,% rsi,% rdx,% rcx,% r8 และ% r9
ดังนั้น%rdi, %rsi, %rdx, %rcx, %r8 and %r9
การลงทะเบียนเพื่อใช้ในการส่งผ่านพารามิเตอร์จำนวนเต็ม / ตัวชี้ (เช่นชั้น INTEGER) ไปยังฟังก์ชั่น libc ใด ๆ จากการชุมนุม % rdi ใช้สำหรับพารามิเตอร์ INTEGER ตัวแรก % rsi สำหรับที่ 2,% rdx สำหรับที่ 3 เป็นต้นไป จากนั้นcall
ควรได้รับคำแนะนำ สแต็ก ( %rsp
) ต้องอยู่ในแนว 16B เมื่อcall
ดำเนินการ
หากมีพารามิเตอร์ INTEGER มากกว่า 6 ตัวพารามิเตอร์ INTEGER ที่ 7 และต่อมาจะถูกส่งผ่านไปยังสแต็ก (ผู้โทรปรากฏเช่นเดียวกับ x86-32)
8 จำนวนจุดลอยตัวแรกจะถูกส่งผ่านใน% xmm0-7 ต่อมาบนสแต็ก ไม่มีการบันทึกการลงทะเบียนของเวกเตอร์ (ฟังก์ชั่นที่มีการผสมผสานของ FP และอาร์กิวเมนต์จำนวนเต็มสามารถมีอาร์กิวเมนต์การลงทะเบียนทั้งหมดมากกว่า 8 ข้อ)
ฟังก์ชั่น Variadic ( เช่นprintf
) ต้องการ%al
= จำนวนของการลงทะเบียน FP เสมอ
มีกฎสำหรับการที่จะแพ็ค structs เข้าสู่รีจิสเตอร์ ( rdx:rax
เมื่อคืน) เทียบกับในหน่วยความจำ ดู ABI สำหรับรายละเอียดและตรวจสอบผลลัพธ์คอมไพเลอร์เพื่อให้แน่ใจว่าโค้ดของคุณเห็นด้วยกับคอมไพเลอร์เกี่ยวกับวิธีส่งผ่าน / ส่งคืนบางสิ่งบางอย่าง
โปรดทราบว่าการเรียกใช้ฟังก์ชัน Windows x64มีความแตกต่างที่สำคัญหลายอย่างจาก x86-64 System V เช่นพื้นที่เงาที่ต้องสำรองไว้โดยผู้โทร (แทนที่จะเป็นโซนสีแดง) และ xmm6-xmm15 ที่สงวนการโทรไว้ และกฎที่แตกต่างกันมากสำหรับ arg ซึ่งไปในการลงทะเบียน