__Gxx_personality_v0 ne için?


103

Bu, bir işletim sistemi geliştirme sitesinden gelen ikinci el bir soru, ancak hiçbir yerde düzgün bir açıklama bulamadığım için beni meraklandırdı.

Gcc kullanarak bağımsız bir C ++ programını derlerken ve bağlarken bazen bunun gibi bir bağlayıcı hatası oluşur:

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

Bunun nedeni görünüşe göre bu sembolün, bağımsız bir ortamda eksik olan libstdc ++ 'da tanımlanmış olmasıdır. Sorunu çözmek basitçe bu sembolü bir yerde tanımlamayı gerektirir:

void *__gxx_personality_v0;

Hangisi güzel, ama sadece sihirli bir şekilde çalışan şeyleri sevmiyorum ... Yani soru şu, bu sembolün amacı nedir?

Yanıtlar:


93

Örneğin başka bir soruya verdiğim cevabın montaj çıktısında görebileceğiniz yığın çözülme tablolarında kullanılır . Bu yanıtta belirtildiği gibi, kullanımı Kişilik Rutini olarak adlandırılan Itanium C ++ ABI tarafından tanımlanmaktadır .

Global bir NULL void işaretçisi olarak tanımlayarak "çalışmasının" nedeni, muhtemelen hiçbir şeyin bir istisna atmamasıdır. Bir şey bir istisna atmaya çalıştığında, yanlış davrandığını göreceksiniz.

Elbette, istisnaları hiçbir şey kullanmıyorsa, ile bunları devre dışı bırakabilirsiniz -fno-exceptions(ve hiçbir şey RTTI kullanmıyorsa, ayrıca ekleyebilirsiniz -fno-rtti). Bunları kullanıyorsanız, (daha önce belirtildiği gibi) g++yerine ile bağlantı kurmanız gerekir gcc, bu -lstdc++sizin için ekleyecektir .


2
Bahşiş için teşekkürler -fno-exceptions. CPPFLAGS += -fno-exceptionsMakefile dosyama ekledim ve bu hatayı çözdü.
Alan Kinnaman

12

İstisna işlemenin bir parçasıdır. Gcc EH mekanizması çeşitli EH modellerini karıştırmaya izin verir ve bir istisna eşleşmesi olup olmadığını, hangi sonlandırmanın başlatılacağını vb. Belirlemek için bir kişilik rutini başlatılır. Bu özel kişilik rutini C ++ istisna işleme içindir (örneğin, gcj / Java istisna işleme).


11

İstisna işleme, bağımsız uygulamalara dahildir.

Bunun nedeni, muhtemelen gcckodunuzu derlemek için kullanmanızdır . Eğer seçenek ile derlerseniz, linker sürecini çağırdığında linker -###seçeneğinin eksik olduğunu fark edeceksiniz -lstdc++. İle derleme g++, bu kitaplığı ve dolayısıyla içinde tanımlanan sembolleri içerecektir.


Her zaman g ++ ile derlemenin sadece derleyiciye kodun C ++ olduğunu söylemek istediğinizde gerekli olduğunu düşündüm (örneğin, eksik uzantı). Görünüşe göre C ++ kodunu gcc ile derlemek, gelen kitaplıkların dahil edilmesini kaçırıyor. Dışında bazı kütüphaneler eksik gelen, gözlerimi derleme diğer bazı "yan etkiler" vardır file.cppile gccyerine g++?
Lazer

1
@eSkay bildiğim kadarıyla libstdc++, ikisi arasındaki tek fark bağlantısı .
Johannes Schaub -

6

libstd++Kod tabanındaki hızlı bir grep , aşağıdaki iki kullanımı ortaya çıkardı __gx_personality_v0:

Libsupc ++ / çözme-cxx.h içinde

// 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 içinde

#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 ...
}

(Not: Aslında bundan biraz daha karmaşık; bazı ayrıntıları değiştirebilecek bazı koşullu derlemeler var).

Bu nedenle, kodunuz aslında istisna işlemeyi kullanmadığı sürece, sembolü void*hiçbir şeyi etkilemeyecek şekilde tanımlayın , ancak bunu yapar yapmaz çökeceksiniz - __gxx_personality_v0global bir nesne değil, bir işlevdir. fonksiyonu çağırmak 0 adresine atlayacak ve bir segfault'a neden olacaktır.


0'a mutlaka atlamak gerekmez; global başlatılmamış olduğundan herhangi bir değer olabilir, gerçekten.
strager

6
strager, programcı onları başlatmazsa sıfır başlatılır
Johannes Schaub - litb

@litb: Bu yalnızca çekirdek bss bölümünü sıfırlamayı uyguluyorsa doğrudur :-P. Ama evet, akıl sağlığı için 0 başlatılmalılar.
Evan Teran

9
@Evan Teran: Hayır, uyumlu bir C uygulaması her zaman globalleri 0 olarak başlatacaktır. Bkz. C99 standardı §5.1.2 ve §6.7.8 paragraf 10.
Adam Rosenfield

6

Bu hatayı bir kez yaşadım ve kaynağını buldum:

Bir gcc derleyici kullanıyordum ve dosyam CLIENT.Cbir C ++ programı değil de bir C programı yapıyor olmama rağmen çağrıldı .

gcc, .Cuzantıyı C ++ programı ve .cuzantıyı C programı olarak tanır (küçük c ve büyük C'ye dikkat edin).

Bu yüzden dosya CLIENT.cprogramımı yeniden adlandırdım ve işe yaradı.


2

Yukarıdaki cevaplar doğrudur: istisna işlemede kullanılır. Kılavuzu GCC sürüm 6 (versiyon 7 el artık mevcut olan) daha fazla bilgi vardır. Hata, GCC tarafından bilinmeyen harici bir işlevi bağlarken Java istisnaları atarken ortaya çıkabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.