เคอร์เนลมีฟังก์ชั่น main () หรือไม่? [ปิด]


52

ฉันกำลังเรียนรู้ไดรเวอร์อุปกรณ์และการเขียนโปรแกรมเคอร์เนล ตามหนังสือของ Jonathan Corbet ไม่มีmain()ฟังก์ชั่นในไดรเวอร์อุปกรณ์

ดังนั้นฉันสองคำถาม:

  • ทำไมเราไม่ต้องการmain()ฟังก์ชั่นในไดรเวอร์อุปกรณ์?
  • เคอร์เนลมีmain()ฟังก์ชั่นหรือไม่?

มีคนอธิบายเรื่องนี้กับฉันได้ไหม


1
ถามผู้ใช้คนเดียวกันด้วยที่นี่: stackoverflow.com/q/18266063/827263
Keith Thompson

@ KeithThompson ... ใช่ ... เพียงเพราะฉันไม่ได้รับคำตอบในสิ่งที่ฉันต้องการดังนั้นฉันจึงถามที่นี่
คนที่

@Shadur ... อย่างไรก็ตามตอนนี้มันกำลังจะปิด ... และฉันไม่มีสิทธิ์พิเศษที่จะย้ายข้อมูล ...
ใครบางคนที่

นี้ควรได้รับการปิดวิธีอื่น ๆ คนนี้มีมุมมองที่มากขึ้น :-)
Ciro Santilli新疆改造中心法轮功六四事件

คำตอบ:


82

ในโปรแกรมผู้ใช้พื้นที่main()คือจุดเริ่มต้นไปยังโปรแกรมที่เรียกโดยรหัสเริ่มต้น libcเมื่อดำเนินการไบนารี รหัสเคอร์เนลไม่มีความหรูหราที่จะพึ่งพา libc เนื่องจาก libc นั้นอาศัยเคอร์เนลอินเตอร์เฟส syscall สำหรับการจัดสรรหน่วยความจำ, I / O, การจัดการกระบวนการ ฯลฯ

ที่กล่าวว่าเทียบเท่ากับmain()ในรหัสเคอร์เนลคือstart_kernel()ซึ่งเรียกโดย bootloaderหลังจากโหลดภาพเคอร์เนลแตกมันลงในหน่วยความจำและการตั้งค่าฮาร์ดแวร์ที่จำเป็นและเพจจิ้งหน่วยความจำ start_kernel()ทำการตั้งค่าระบบเป็นส่วนใหญ่และในที่สุดจะเกิดกระบวนการเริ่มต้น

จุดเริ่มต้นไปยังโมดูลเคอร์เนล Linux เป็นฟังก์ชัน init ที่ลงทะเบียนกับเคอร์เนลโดยเรียกmodule_init()มาโคร ฟังก์ชั่นโมดูลเริ่มต้นที่ลงทะเบียนนั้นถูกเรียกโดยรหัสเคอร์เนลผ่านdo_initcalls()ฟังก์ชั่นระหว่างการเริ่มต้นเคอร์เนล


11
ขอบคุณสำหรับการตระหนักถึงวัตถุประสงค์ที่แท้จริงของmainวิธีการใน C (มันเป็นความเข้าใจผิดที่ถือกันโดยทั่วไปว่าระบบปฏิบัติการเรียกโดยตรงmainซึ่งไม่ใช่กรณีและแม้แต่น้อยในกรณีเช่น C ++) ฉัน ' ฉันจะยกระดับการโหวตให้คุณอีกถ้าฉันสามารถทำได้
CVn

1
@Thomas ... ขอบคุณสำหรับคำตอบที่ยอดเยี่ยมนี้ ....
มีคน

17

เคอร์เนลไม่มีmainฟังก์ชั่น mainเป็นแนวคิดของภาษา C เคอร์เนลเขียนใน C และชุดประกอบ รหัสรายการของเคอร์เนลเขียนโดยชุดประกอบ

ลำดับการบู๊ตถูกจัดระเบียบดังนี้:

  1. BIOS จะโหลดตัวโหลดบูตจากอุปกรณ์บล็อกการบูต ตัวโหลดบูตยอดนิยมในขณะนี้คือด้วง
  2. ด้วงโหลดภาพ kernel ลงในหน่วยความจำที่เป็นไปได้กับอุปกรณ์รากเริ่มต้น ( initrd) จากนั้นโค้ดที่ที่อยู่บางส่วนจะถูกดำเนินการ
  3. อิมเมจเคอร์เนลมีโมดูลเคอร์เนลบางตัวอย่างเช่น: โมดูลระบบไฟล์ไดรเวอร์อุปกรณ์ อิมเมจเคอร์เนลใช้โมดูลระบบไฟล์เพื่อเมาท์ระบบไฟล์รูท ตอนนี้เคอร์เนลสามารถโหลดและรันโมดูลเคอร์เนลทั้งหมดจากดิสก์
  4. เคอร์เนลรันภารกิจการเริ่มต้น ตัวอย่างเช่น: สำรวจบัส PCI และค้นหาอุปกรณ์ PCI ทั้งหมดเตรียมใช้งานไดรเวอร์อุปกรณ์ทั้งหมด
  5. ในที่สุดเคอร์เนลสร้างกระบวนการ 0 และกระบวนการ 1 ( initกระบวนการ) สลับบริบทของ CPU จากแหวน 0 เป็นแหวน 3 และเริ่มต้นกระบวนการเริ่มต้น (กระบวนการ id คือ 1) ตอนนี้การบูตเคอร์เนลเสร็จสิ้นแล้ว!
  6. initโปรแกรมเรียกใช้สคริปต์ init ทั้งหมด บริการทั้งหมดเริ่มต้นแล้ว เชลล์เรียกว่า ผู้ใช้สามารถเข้าสู่ระบบ

mainฟังก์ชั่นเป็นฟังก์ชัน C จริง ๆ แล้ววิธีการหลักไม่ใช่จุดเริ่มต้นของโปรแกรม C รันไทม์ C เรียกใช้ฟังก์ชันมากมายก่อนหน้าmainนี้ GCC มีคุณสมบัติเพิ่มเติม: ตัวสร้าง ฟังก์ชั่นประกาศว่า "คอนสตรัค" mainก่อนที่จะถูกเรียกว่า

ตัวอย่างเช่น:

/* This should not be used directly. Use block_init etc. instead. */ 
#define module_init(function, type) \
    static void _attribute__((constructor)) do_qemu_init ## function(void) { \
    register_module_init(function, type); \
} 

มาโครนี้มาจากโครงการ qemu


วิธีการหลักคือวิธีการ AC วิธีการหลักที่แท้จริงไม่ได้เป็นรายการของ c program.C runtime ได้เรียกวิธีการมากมายก่อนวิธีการหลัก
Edward Shen

โดยทั่วไปไบออสจะโหลดตัวโหลดบูตและบูตตัวโหลดนั้นจะโหลดอิมเมจเคอร์เนล (และอาจเป็นแบบเริ่มต้น) รหัสของเคอร์เนลอยู่ในรูปเคอร์เนลไม่ใช่ initrd
Stéphane Chazelas

GCC มีคุณสมบัติเพิ่มเติม: ตัวสร้าง การประกาศเมธอด "ตัวสร้าง" ถูกเรียกก่อนเมธอดหลัก ตัวอย่างเช่น: / * สิ่งนี้ไม่ควรใช้โดยตรง ใช้ block_init ฯลฯ แทน * / #define module_init (ฟังก์ชัน, ประเภท) \ static void _attribute __ ((constructor)) do_qemu_init ## ฟังก์ชัน (void) {\ register_module_init (ฟังก์ชัน, ประเภท); \}
Edward Shen

1
initrd.img ไม่ใช่ภาพเคอร์เนล เป็นชุดของโมดูลที่โหลดโดยเคอร์เนลเมื่อบูต ภาพเคอร์เนลมักจะมีชื่อขึ้นต้นด้วย "vmlinuz" แต่แตกต่างจาก distro ไป distro
goldilocks

3
คำตอบนี้เต็มไปด้วย "ทุกอย่างเป็น PC / Linux / i86" และมันบูทอย่างนั้นและเคอร์เนลก็เป็นอย่างนั้น ... ทำไมทุกคนคิดว่ามันเป็นวิธีเดียวที่เป็นไปได้ในโลก?
เจนส์

9

มีฟังก์ชั่นหลัก () ในarch / x86 / boot / main.cสำหรับการเตรียมระบบเพื่อเปลี่ยนจากโหมดจริงเป็นโหมดที่ได้รับการป้องกัน แต่สถาปัตยกรรมอื่น ๆ ไม่มีรหัสดังกล่าว มีภาพรวมที่ดีเกี่ยวกับการบูทเคอร์เนล 2.6.x บนแพลตฟอร์ม x86 มันคุ้มค่าที่จะอ่านมัน

ตามเอกสารHOWTO ทำการพัฒนาเคอร์เนลลินุกซ์

สภาพแวดล้อม C อิสระที่ไม่มีการพึ่งพาไลบรารี C มาตรฐานดังนั้นบางส่วนของมาตรฐาน C ไม่ได้รับการสนับสนุน

สิ่งที่เป็นไปตามมาตรฐาน BTW C หมายความว่า

มันเป็นการใช้งานที่กำหนดว่าต้องมีโปรแกรมในสภาพแวดล้อมอิสระเพื่อกำหนดฟังก์ชั่น 'หลัก'

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