2011-11-30 8 views
6

Câu hỏi này liên quan đến this one cũng như câu trả lời của nó.Trộn các đối tượng PIC và không phải PIC trong một thư viện chia sẻ

Tôi vừa phát hiện ra một số sự xấu xí trong bản dựng mà tôi đang nghiên cứu. Tình hình trông giống như sau (được viết bằng định dạng gmake); lưu ý, điều này đặc biệt áp dụng đối với một mô hình bộ nhớ 32-bit trên sparc và x86 phần cứng:

OBJ_SET1 := some objects 
OBJ_SET2 := some objects 

# note: OBJ_SET2 doesn't get this flag 
${OBJ_SET1} : CCFLAGS += -PIC 

${OBJ_SET1} ${OBJ_SET2} : %.o : %.cc 
    ${CCC} ${CCFLAGS} -m32 -o ${@} -c ${<} 

obj1.o  : ${OBJ_SET1} 
obj2.o  : ${OBJ_SET2} 
sharedlib.so : obj1.o obj2.o 
obj1.o obj2.o sharedlib.so : 
    ${LINK} ${LDFLAGS} -m32 -PIC -o ${@} ${^} 

Rõ ràng nó có thể làm việc để trộn đối tượng biên soạn có và không có PIC trong một đối tượng chia sẻ (điều này đã được sử dụng trong nhiều năm qua) . Tôi không biết đủ về PIC để biết liệu đó có phải là một ý tưởng hay hay không, và tôi đoán là trong trường hợp này nó không cần thiết, nhưng thay vào đó nó xảy ra vì ai đó không quan tâm đủ để tìm ra cách đúng đắn để làm điều đó khi tacking về công cụ mới để xây dựng.

Câu hỏi của tôi là:

  1. là an toàn
  2. Đây có phải là một ý tưởng tốt
  3. gì vấn đề tiềm ẩn có thể xảy ra như là kết quả
  4. Nếu tôi chuyển đổi tất cả mọi thứ để PIC, được có bất kỳ phi - những thứ mà tôi có thể muốn xem.

Trả lời

4

Quên tôi thậm chí đã viết câu hỏi này.

Một số giải thích là theo thứ tự đầu tiên:

  • Non-PIC mã có thể được nạp bởi hệ điều hành vào bất kỳ vị trí trong bộ nhớ trong [nhất?] OS hiện đại. Sau khi tất cả mọi thứ được tải, nó đi qua một giai đoạn sửa chữa các phân đoạn văn bản (nơi mà các công cụ thực thi kết thúc) để nó địa chỉ chính xác các biến toàn cầu; để tắt chức năng này, đoạn văn bản phải ghi được.
  • Dữ liệu thực thi PIC có thể được tải một lần bởi hệ điều hành và được chia sẻ trên nhiều người dùng/quy trình. Tuy nhiên, để hệ điều hành làm điều này, phân đoạn văn bản phải là chỉ đọc - có nghĩa là không có bản sửa lỗi. Mã được biên dịch để sử dụng Bảng bù trừ toàn cầu (GOT) để nó có thể giải quyết các hình cầu liên quan đến GOT, làm giảm nhu cầu sửa lỗi.
  • Nếu một đối tượng được chia sẻ được xây dựng mà không có PIC, mặc dù nó được khuyến khích mạnh mẽ nhưng dường như không cần thiết; nếu hệ điều hành phải sửa chữa các phân đoạn văn bản thì nó buộc phải tải nó vào bộ nhớ được đánh dấu đọc-ghi ... mà ngăn ngừa chia sẻ trên các quy trình/người dùng.
  • Nếu một nhị phân thực thi được xây dựng/với/PIC, tôi không biết những gì đi sai dưới mui xe nhưng tôi đã chứng kiến ​​một vài công cụ trở nên không ổn định (tai nạn bí ẩn & tương tự).

Những câu trả lời:

  • Trộn PIC/phi PIC, hoặc sử dụng PIC trong thực thi có thể gây khó dự đoán và theo dõi bất ổn. Tôi không có một lời giải thích kỹ thuật cho lý do tại sao.
    • ... để bao gồm segfaults, lỗi xe buýt, tham nhũng ngăn xếp và có thể nhiều hơn nữa bên cạnh.
  • Không PIC trong các đối tượng được chia sẻ có thể sẽ không gây ra bất kỳ vấn đề nghiêm trọng nào, mặc dù nó có thể dẫn đến sử dụng nhiều bộ nhớ hơn.

cập nhật (4/17)

Tôi đã kể từ khi phát hiện ra nguyên nhân của một số của tai nạn tôi đã thấy trước đó. Để minh họa:

/*header.h*/ 
#include <map> 
typedef std::map<std::string,std::string> StringMap; 
StringMap asdf; 

/*file1.cc*/ 
#include "header.h" 

/*file2.cc*/ 
#include "header.h" 

int main(int argc, char** argv) { 
    for(int ii = 0; ii < argc; ++ii) { 
    asdf[argv[ii]] = argv[ii]; 
    } 

    return 0; 
} 

... sau đó:

$ g++ file1.cc -shared -PIC -o libblah1.so 
$ g++ file1.cc -shared -PIC -o libblah2.so 
$ g++ file1.cc -shared -PIC -o libblah3.so 
$ g++ file1.cc -shared -PIC -o libblah4.so 
$ g++ file1.cc -shared -PIC -o libblah5.so 

$ g++ -zmuldefs file2.cc -Wl,-{L,R}$(pwd) -lblah{1..5} -o fdsa 
#  ^^^^^^^^^ 
#  This is the evil that made it possible 
$ args=(this is the song that never ends); 
$ eval ./fdsa $(for i in {1..100}; do echo -n ${args[*]}; done) 

Đó ví dụ cụ thể không kết thúc đâm, nhưng đó là về cơ bản tình hình đã tồn tại trong mã của nhóm đó. Nếu nó hiện tai nạn nó có thể sẽ có trong destructor, thường là một lỗi đôi miễn phí.

Nhiều năm trước, họ đã thêm -zmuldefs vào bản dựng của họ để loại bỏ các lỗi biểu tượng được xác định nhân. Trình biên dịch phát ra mã để chạy các constructor/destructors trên các đối tượng toàn cầu. -zmuldefs buộc chúng phải sống ở cùng một vị trí trong bộ nhớ nhưng nó vẫn chạy các hàm tạo/huỷ một lần cho exe và mỗi thư viện bao gồm tiêu đề vi phạm - do đó không có đôi.