2009-11-30 7 views
7

여러 개의 공유 라이브러리로 분리되고 플러그인 공유 라이브러리에서 추가 기능을로드하는 크로스 플랫폼 C++ 응용 프로그램이 있습니다. 플러그인 라이브러리는 호출 응용 프로그램에 대한 지식이나 종속성이 없어도 자체적으로 포함되고 함수로 간주됩니다.중복 심볼이있는 C++ 플러그인 라이브러리의 Segfault

플러그인 중 하나에 주 응용 프로그램의 복사 된 코드가 포함되어 있으므로 엔진의 코드 이름과 중복되는 기호 이름이 포함되어 있습니다. (네, 그렇습니다. 일반적으로 플러그 - 인이 작성된 시점에 엔진은 모 놀리 식 바이너리 였고 라이브러리를 공유 할 수 없었습니다.) Windows에서 모든 것이 정상적으로 실행됩니다. Linux에서 우리는 segfault를 얻고있었습니다. 오류의 스택 추적을 보면 복제 클래스 이름에서 함수를 호출 할 때 플러그인에서 발생했습니다. 약간 다른 버전의 공유 코드가있는 엔진과 플러그인의 결과 인 것으로 보입니다 (일부 클래스 기능은 플러그인에서 주석 처리되었습니다). 마치 플러그인이 심볼 대신 런타임 엔진에 링크 된 심볼을 얻는 것처럼 보였습니다. dlopen의 매개 변수를 dlopen(pFilepath, RTLD_LAZY | RTLD_LOCAL)으로 변경하여 문제를 수정했습니다.

그러나 엔진을 다시 작성하여 공유 라이브러리로 분할하면 (플러그인에서 최종 용도로 사용하기 위해) segfault 오류가 다시 발생합니다. 그리고 스택 트레이스를 보면, 엔진 -> 플러그인 -> 엔진이됩니다.

런타임 링커가 플러그인의 심볼을 엔진에 매핑하지 않도록 지정하는 방법이 있습니까 (특히 플러그인에서 정의 된 경우)?

감사합니다. 매트


편집 2009년 12월 3일

내가 먼저 자신의 네임 스페이스에 플러그인의 코드를 포장했습니다. 그것은 엔진에 링크되어있는 라이브러리에 정적으로 연결되어 있기 때문에 작동하지 않습니다. 정적 라이브러리의 버전이 다르므로 segfault!

그런 다음 엔진의 빌드를 변경하고 라이브러리를 정적으로 링크했습니다. 그리고 그것을 실행할 때 더 이상 문제가 없습니다. 따라서 공유 라이브러리 심볼을 내 보낸 다음 패키지를 열 때 동적으로 플러그인으로 재배치 된 결과입니다. 그러나 엔진의 모든 코드가 단일 실행 파일에있을 때 심볼을 내보내지 않으므로 (플러그인의 심볼을 엔진으로 재배치하려고하지는 않습니다).

Open-MPI를 사용하는 프로그램의 병렬화 된 버전이 있고 여전히 segfault를 얻으므로 여전히 문제가 있습니다. 그것은 여전히 ​​엔진 심볼을 내보내고 플러그인을 재배치한다는 점에서 나타납니다. 이는 Open-MPI가 응용 프로그램을 실행하는 방법과 관련이 있습니다.

런타임에 심볼을 동적으로 재배치하지 않는다는 것을 알려주는 플러그인 공유 라이브러리에서 사용할 수있는 링커 플래그가 있습니까? 또는 기호를 숨기면 이동하지 않습니다. -s ("모든 기호 정보 생략")을 시도했지만 분명히 동적 기호가 변경되지 않았습니다 (nm -D <plugin>을 사용하여 확인).

+0

이러한 기호는 전역 또는 함수 이름입니까? 코드를 약간 변경할 수 있습니까? –

+0

이들은 클래스 및 해당 멤버 함수입니다. 엔진 코드베이스에서 36 개의 파일이 사용되므로 각 클래스 이름이나 파일을 수정하고 싶지 않습니다. 최종 목표는 시간 제약과 코드 유효성 검사로 인해 플러그인을 다시 작성하는 것이지만, 필자는 그렇게하지 않으려 고하지 않습니다. – CuppM

+0

@CuppM, 예를 들어, "bar"멤버가 2 곳 정의 된 "Foo"클래스가 있습니까? "Foo"는 두 경우 모두 동일한 네임 스페이스에 있습니다. 그렇다면 이것은 결코 당신을 위해 제대로 작동하지 않을 것입니다. "Foo"중 하나를 자신의 네임 스페이스로 이동하면 인생이 더 쉬워집니다. – Glen

답변

4

나는 솔루션, 링커 플래그 -Bsymbolic 발견했습니다 생각합니다. 기본적으로이 플래그는 공유 라이브러리에 플래그를 추가하여 런타임 링커가 먼저 심볼 이름을 자체적으로 시도하고 해석하도록 지시합니다. 엔진은 플러그인이 그 플래그와 링크되었을 때 모든 경우에 (단조로운 exe, exe w/공유 라이브러리, 네임 스페이스를 감싸고있는/쓰지 않는/w/o) 플러그인으로 실행할 수있었습니다.

-Bsymbolic에 대한 경고와 함께 몇 가지 냐는 것 같다 않습니다
http://www.technovelty.org/code/c/bsymbolic.html
http://software.intel.com/en-us/articles/performance-tools-for-software-developers-bsymbolic-can-cause-dangerous-side-effects/

그러나 그들의 경고와 어떤 플러그인의 의도이며, 나는 그것이 나에게 맞는 옵션 생각을 고려. 적어도 지금은.

1

나는 Glen에 동의한다. 네임 스페이스를 통해 클래스 이름을 수정하지 않으면 정말 해결할 수 없다. 36 개의 파일조차도 심볼 이름을 변경하지 않고 안정적으로 수정하는 것보다 수정하는 데 시간이 덜 걸릴 것입니다.

이름을 조정해야하는 모든 클래스를 식별하여 시작하십시오. 당신의 링커가 아마 당신을 위해 그것들을 나열 할 것입니다. 그런 다음 의 이름을 개의 클래스 집합 (Foo에서 Engine :: Foo 및 Plugin :: Foo)으로 변경합니다.그렇게하면 문제가되는 클래스에 대한 모든 참조를 찾기 위해 컴파일러를 얻을 수 있습니다. 플러그인이 올바른 새 플러그인 클래스 이름에 대한 참조와 함께 컴파일 될 때까지 플러그인 소스를 멀리합니다. 일단 완료되면 Engine :: 클래스를 이전 이름으로 다시 변경하십시오 (엔진 소스를 영구히 수정하지 않는 한, 그렇지 않은 것처럼 들립니다). 이제 플러그인이 고유 한 이름의 올바른 클래스로 컴파일되고 링크되어야합니다.

+0

아마 이것에 대해 옳은 동안. 만족할만한 대답은 아니므로, 잠시 후에 답변을 드리겠습니다. 플러그인 코드를 수정하여 문제의 비트에 네임 스페이스를 추가합니다. 엔진의 공유 라이브러리를 사용하여 다시 작성할 수있을 때까지는 엔진의 모든 코드를 변경 했으므로 복사본을 수정해도 문제가되지 않습니다. – CuppM

0

나는 PluginX 네임 스페이스로 모든 플러그인 코드를 감쌀 것이다. 그건 분명히 이러한 오류에서 당신을 저장할 수 있습니다. 어쨌든 매우 중요하고 중요한 연습입니다.