__gxx_personality_v0 คืออะไร?


103

นี่เป็นคำถามมือสองจากไซต์การพัฒนาระบบปฏิบัติการ แต่มันทำให้ฉันสงสัยเพราะฉันไม่สามารถหาคำอธิบายที่ดีได้จากที่ใด

เมื่อรวบรวมและเชื่อมโยงโปรแกรม C ++ แบบอิสระโดยใช้ gcc บางครั้งข้อผิดพลาดของตัวเชื่อมโยงเช่นนี้จะเกิดขึ้น:

out/kernel.o:(.eh_frame+0x11): undefined reference to `__gxx_personality_v0'

เห็นได้ชัดว่าเป็นเพราะสัญลักษณ์นี้ถูกกำหนดใน libstdc ++ ซึ่งขาดหายไปในสภาพแวดล้อมอิสระ การแก้ไขปัญหาเพียงแค่กำหนดสัญลักษณ์นี้ไว้ที่ใดที่หนึ่ง:

void *__gxx_personality_v0;

ซึ่งดี แต่ฉันไม่ชอบสิ่งที่ใช้งานได้อย่างมหัศจรรย์ ... คำถามคือจุดประสงค์ของสัญลักษณ์นี้คืออะไร?

คำตอบ:


93

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

เหตุผลที่มัน "ใช้งานได้" โดยกำหนดให้เป็น global NULL void pointer อาจเป็นเพราะไม่มีข้อยกเว้น เมื่อมีบางสิ่งพยายามโยนข้อยกเว้นคุณจะเห็นว่ามันทำงานผิดปกติ

แน่นอนว่าหากไม่มีสิ่งใดใช้ข้อยกเว้นคุณสามารถปิดใช้งานได้ด้วย-fno-exceptions(และหากไม่มีอะไรใช้ RTTI คุณสามารถเพิ่มได้-fno-rtti) หากคุณใช้พวกเขาคุณต้องเชื่อมโยง (ตามที่คำตอบอื่น ๆ ระบุไว้แล้ว)g++แทนgccซึ่งจะเพิ่ม-lstdc++ให้คุณ


2
-fno-exceptionsขอบคุณสำหรับเคล็ดลับเกี่ยวกับ ฉันเพิ่มลงCPPFLAGS += -fno-exceptionsใน makefile ของฉันและแก้ไขข้อผิดพลาดได้
Alan Kinnaman

12

เป็นส่วนหนึ่งของการจัดการข้อยกเว้น กลไก gcc EH ช่วยให้สามารถผสมโมเดล EH ต่างๆได้และมีการเรียกรูทีนของบุคลิกภาพเพื่อพิจารณาว่าการจับคู่ข้อยกเว้นการสรุปสิ่งที่จะเรียกใช้ ฯลฯ รูทีนบุคลิกภาพเฉพาะนี้ใช้สำหรับการจัดการข้อยกเว้น C ++ (ในทางตรงกันข้ามกับ gcj / Java การจัดการข้อยกเว้น)


11

การจัดการข้อยกเว้นรวมอยู่ในการใช้งานสถานะอิสระ

เหตุผลนี้คือคุณอาจใช้gccเพื่อรวบรวมโค้ดของคุณ หากคุณคอมไพล์ด้วยตัวเลือก-###คุณจะสังเกตเห็นว่าไม่มีตัวเลือกตัวเชื่อมโยง-lstdc++เมื่อเรียกใช้กระบวนการตัวเชื่อมโยง การคอมไพล์ด้วยg++จะรวมไลบรารีนั้นและสัญลักษณ์ที่กำหนดไว้ในนั้น


ฉันคิดเสมอว่าการคอมไพล์ด้วย g ++ นั้นจำเป็นเฉพาะเมื่อคุณต้องการบอกคอมไพเลอร์โดยเฉพาะว่าโค้ดคือ C ++ (ตัวอย่างเช่น - ส่วนขยายที่ขาดหายไป) ตอนนี้ดูเหมือนว่าการรวบรวมโค้ด C ++ ด้วย gcc จะพลาดการรวมไลบรารี come นอกเหนือจากการขาดไลบรารีบางส่วนแล้วยังมี "ผลข้างเคียง" อื่น ๆ ของการรวบรวม my file.cppwith gccแทนg++หรือไม่?
Lazer

1
@eSkay เท่าที่ฉันรู้การเชื่อมโยงlibstdc++เป็นข้อแตกต่างเพียงอย่างเดียวระหว่างทั้งสอง
Johannes Schaub - litb

6

grep อย่างรวดเร็วของlibstd++ฐานรหัสเผยให้เห็นสองลักษณะต่อไปนี้ของ__gx_personality_v0:

ใน libsupc ++ / unind-cxx.h

// GNU C++ personality routine, Version 0.                                      
extern "C" _Unwind_Reason_Code __gxx_personality_v0
     (int, _Unwind_Action, _Unwind_Exception_Class,
      struct _Unwind_Exception *, struct _Unwind_Context *);

ใน libsupc ++ / eh_personality.cc

#define PERSONALITY_FUNCTION    __gxx_personality_v0
extern "C" _Unwind_Reason_Code
PERSONALITY_FUNCTION (int version,
                      _Unwind_Action actions,
                      _Unwind_Exception_Class exception_class,
                      struct _Unwind_Exception *ue_header,
                      struct _Unwind_Context *context)
{
  // ... code to handle exceptions and stuff ...
}

(หมายเหตุ: จริงๆแล้วมันซับซ้อนกว่านั้นเล็กน้อยมีการรวบรวมตามเงื่อนไขที่สามารถเปลี่ยนแปลงรายละเอียดบางอย่างได้)

ดังนั้นตราบใดที่รหัสของคุณไม่ได้ใช้การจัดการข้อยกเว้นการกำหนดสัญลักษณ์ว่าvoid*จะไม่ส่งผลกระทบใด ๆ แต่ทันทีที่ทำคุณจะผิดพลาด - __gxx_personality_v0เป็นฟังก์ชันไม่ใช่วัตถุระดับโลกดังนั้นการพยายาม ในการเรียกใช้ฟังก์ชันจะข้ามไปยังที่อยู่ 0 และทำให้เกิด segfault


ไม่จำเป็นต้องข้ามไปที่ 0; ทั่วโลกไม่ได้กำหนดค่าเริ่มต้นดังนั้นอาจเป็นค่าใดก็ได้จริงๆ
strager

6
strager, globals จะเริ่มต้นเป็นศูนย์หากโปรแกรมเมอร์ไม่เริ่มต้น
Johannes Schaub - litb

@litb: นี่จะเป็นจริงก็ต่อเมื่อเคอร์เนลใช้ส่วน bss เป็นศูนย์ :-P แต่ใช่ควรเริ่มต้นเป็น 0 เพื่อความมีสุขภาพจิต
Evan Teran

9
@Evan Teran: ไม่การใช้งาน C ที่สอดคล้องกันจะเริ่มต้น globals เป็น 0 เสมอดู§5.1.2และ§6.7.8วรรค 10 ของมาตรฐาน C99
Adam Rosenfield

6

ฉันมีข้อผิดพลาดนี้หนึ่งครั้งและพบที่มา:

ฉันใช้คอมไพเลอร์ gcc และไฟล์ของฉันถูกเรียก CLIENT.Cทั้งๆที่ฉันใช้โปรแกรม C ไม่ใช่โปรแกรม C ++

gcc รู้จัก.Cส่วนขยายเป็นโปรแกรม C ++ และ.cส่วนขยายเป็นโปรแกรม C (โปรดระวัง c ตัวเล็กและ C ตัวใหญ่)

ดังนั้นฉันจึงเปลี่ยนชื่อCLIENT.cโปรแกรมไฟล์ของฉันและมันใช้งานได้


2

คำตอบข้างต้นถูกต้อง: ใช้ในการจัดการข้อยกเว้น คู่มือสำหรับ GCC รุ่น 6 มีข้อมูลเพิ่มเติม (ซึ่งไม่ได้อยู่ในรุ่น 7 ด้วยตนเอง) ข้อผิดพลาดอาจเกิดขึ้นเมื่อเชื่อมโยงฟังก์ชันภายนอกที่ GCC ไม่รู้จัก - ส่งข้อยกเว้น Java

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