Проектът Free Pascal/C++ се срива в cout::sentry

Имам смесен Free Pascal/C++ проект. Debian 5.0 ("Lenny") на i386, FPC 2.4.4. Когато стартирам програмата, тя се срива при първото cout<< извикване. Забавно, работеше известно време; някоя актуализация на ОС вероятно го е счупила. Ето изолирания проблем:

p.pas:

{$L c.o}    
program p;
uses initc;
procedure Hello; cdecl; external name 'Hello';

begin
     Hello;
end.     

c.cpp:

#include <iostream>
//void * __dso_handle; //You might need to uncomment that
extern "C" void Hello()
{
    std::cout << "Hello world";
}

Makefile:

p : c.o p.pas Makefile
    fpc p.pas -k-lstdc++

c.o : c.cpp
    g++ -c c.cpp

Make, run, segfault. Пробвано на чисто нова Debian VM - същият резултат.

Сривът се случва в рамките на basic_fstream::sentry::sentry(). Те твърдят, че това местоположение на срив е в съответствие с глобалния cout обект, който не е инициализиран. Това е странно - мислех, че използването на initc от страната на Pascal гарантира, че глобалните C++ променливи са инициализирани.

Някакви идеи, моля? Може ли по някакъв начин да е версията на libstdc++, срещу която правя връзка (това е libstdc++.so.6.0.10)?

РЕДАКТИРАНЕ: става все по-странно и по-странно. Пускам същия двоичен файл (p) на кутия CentOS 5.3 - работи както е рекламирано. Така че вероятно става дума за споделени версии на библиотеки... Ще отида да събера малко повече статистики за различни Linuces.

РЕДАКТИРАНЕ 2: едно нещо, което забелязах: когато направя ldd p на моя Debian box, ето какво получавам:

linux-gate.so.1 =>  (0xb77a6000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb76a6000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb754b000)
libm.so.6 => /lib/i686/cmov/libm.so.6 (0xb7524000)
/lib/ld-linux.so.2 (0xb77a7000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb7517000)

И когато направя същото в кутията на CentOS, където работи:

libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7ec2000)
libc.so.6 => /lib/libc.so.6 (0xb7d69000)
libm.so.6 => /lib/libm.so.6 (0xb7d40000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb7d34000)
/lib/ld-linux.so.2 (0xb7fb7000)

Така че всички C библиотеки (само не C++) идват от i686/cmov директория. Машината Debian също има /lib/libc.so.6 и е различна от тази в cmov. Каква е работата с тази cmov директория? И защо две различни копия на libc с едно и също име?

РЕДАКТИРАНЕ: дори в CentOS глобалните конструктори не се извикват - просто се тестват с ad-hoc глобален обект. Просто не се срива в sentry() по някаква причина. Изглежда, че все пак това е проблем с FPC. Има доклад за грешка във FPC относно това поведение.


person Seva Alekseyev    schedule 17.11.2011    source източник
comment
Възможно ли е това да е свързано с конвенциите за повикване? Ами ако добавите __stdcall?   -  person Kerrek SB    schedule 18.11.2011
comment
Това работеше ли някога преди? Мирише на C++ runtime, който не е инициализиран (глобалните ctors/dtors не са извикани например). Използвате ли GNU линкер? Това е по-скоро въпрос на линкер, отколкото на компилатор, и вие не сте предоставили команда за връзка, която използвате...   -  person    schedule 18.11.2011
comment
@KerrekSB cdecl изглежда точно тук и така или иначе, как би могло да има значение за void функция без параметри?   -  person David Heffernan    schedule 18.11.2011
comment
Не мога да видя нищо в никакви документи, което да показва, че initc инициализира среда за изпълнение на C++. Имате ли линк към такъв документ?   -  person David Heffernan    schedule 18.11.2011
comment
Обикновено iostream използва някои трикове, за да гарантира, че потоците са правилно инициализирани дори за изход от конструктори на статични обекти (обикновено това не би било гарантирано поради недефиниран статичен ред на инициализация между единиците за превод). Може би тези трикове не са съвместими с инициализацията от FreePascal.   -  person celtschk    schedule 18.11.2011
comment
@DavidHeffernan: може би, въпреки че все още има въпрос кой настройва и почиства рамката на стека... е, не знам.   -  person Kerrek SB    schedule 18.11.2011
comment
@Vlad: Кълна се, че стана! Стара компилация на проекта (не на тестовия случай) все още работи успешно на друга кутия.   -  person Seva Alekseyev    schedule 18.11.2011
comment
@DavidHeffernan: идеята е взета от тук. Освен това източниците на initc.   -  person Seva Alekseyev    schedule 18.11.2011
comment
Мисля, че initc е свързано с C код. Но вие искате да стартирате C++. Просто бих се свързал динамично, както предлага sehe.   -  person David Heffernan    schedule 18.11.2011
comment
initc не е предназначен като документирана единица. Използва се като мост между libc errno и вътрешната errno, ако има разлика. Той абстрахира името на библиотеката, съдържаща libc, и начините за достъп до errno по безопасен за нишки начин. (които се различават в *nixes). Най-близкият като документация е оригиналният unix rtl проектен документ stack.nl/~marcov/unixrtl .pdf параграф 4.2.1   -  person Marco van de Voort    schedule 18.11.2011
comment
Има ли документиран начин за свързване на FPC към C++? По начин, който извиква глобалните конструктори?   -  person Seva Alekseyev    schedule 19.11.2011
comment
Не, тъй като няма C++. Има различни реализации и компилатори. Първо разберете какво причинява проблема. Може също да е нещо със скрипта за свързване. И тествайте 2.6.0rc1 или trunk, за да сте сигурни, че не инвестирате много работа във вече решени проблеми.   -  person Marco van de Voort    schedule 19.11.2011


Отговори (3)


Наистина, опитах изрично да се свържа със статичен c.o (с всички различни версии на libstdc++. така че можах да намеря в кутията си) и получавам същия вид грешка:

Runtime error 216 at $00007F3B9C9EFAD1
  $00007F3B9C9EFAD1

Скоро ще пробвам с по-стара инсталация. Актуализация Не мога да накарам linking c.o да работи и на Maverick (gcc 4.4.5 и fpc 2.4.0-2ubuntu1.10.10).

Накарах го да работи на моята кутия Natty само след като преминах към динамично свързване:

В p.pas:

{$L c.so}

Makefile

p : c.so p.pas Makefile
    fpc p.pas

c.so : c.cpp
    g++ -shared -fPIC c.cpp -o $@

Бягай

$ LD_LIBRARY_PATH=$PWD
$ ./p
Hello world
person sehe    schedule 17.11.2011
comment
+1 Как генерирате c.so? g++ -c c.cpp не произвежда такъв. - person Seva Alekseyev; 18.11.2011
comment
@SevaAlekseyev О, някак си borked makefile copy paste... Редактиране, готово. Съжалявам за това. - person sehe; 18.11.2011
comment
Tx. Освен ако не се появи по-добър вариант, ще приема това като хубаво евтино решение. - person Seva Alekseyev; 18.11.2011

Initc трябва да накара FPC да превключи кода за стартиране във форма, която извиква glibc инициализатори, които след това трябва да инициират C++ чрез обичайните механизми ctor/dtor.

Имайте предвид, че initc НЕ превключва управлението на паметта на Pascal да използва libmalloc. Pascal кодът ще използва свой собствен сублокатор, който се базира директно на mmap(2)

Тъй като вашите проблеми изглежда също са свързани с разпределението на паметта, опитайте се да използвате единица "cmem" вместо initc, за да принудите времето за изпълнение на pascal да използва libmalloc, част от glibc за управление на паметта.

person Marco van de Voort    schedule 18.11.2011
comment
Същата разлика. :( И не виждам как разпределението на паметта има общо с това, че конструкторите не се извикват. - person Seva Alekseyev; 18.11.2011
comment
Конструкторът може да се провали по тихи начини поради операции в купчината, спиране на веригата от конструктори и кодът за стартиране на FPC може да не открие това (и да прекрати) правилно. Следващата стъпка ще бъде отстраняване на грешки в кода за стартиране и/или тестване с trunk - person Marco van de Voort; 18.11.2011
comment
Вижте редактиране на въпрос. Това не е компилаторът сам по себе си, това е фино взаимодействие между компилатора и системата и/или споделените библиотеки. Освен това това. - person Seva Alekseyev; 18.11.2011
comment
Освен това, ако добавя произволен глобален обект към c.cpp, неговият конструктор също не се извиква. - person Seva Alekseyev; 19.11.2011

Конкретно за cout (както и други глобални потоци), добавянето на следния ред към входната точка на C++ помага:

std::ios_base::Init();

По-големият проблем все още съществува - не се конструират произволни глобални C++ обекти.

person Seva Alekseyev    schedule 18.11.2011