2010-06-30 24 views
22

Gần đây tôi đang xây dựng một thư viện được chia sẻ nhất định (ELF) nhắm mục tiêu kiến ​​trúc x86-64, như thế này:khác biệt trong mã vị trí độc lập: x86 vs x86-64

g++ -o binary.so -shared --no-undefined ... -lfoo -lbar 

này thất bại với các lỗi sau:

relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC

Tất nhiên, điều đó có nghĩa là tôi cần phải xây dựng lại dưới dạng mã độc lập với vị trí, vì vậy nó phù hợp để liên kết vào thư viện được chia sẻ.

Nhưng điều này hoạt động hoàn toàn tốt trên x86 với chính xác cùng một đối số xây dựng. Vì vậy, câu hỏi là, làm thế nào là di dời trên x86 khác nhau từ x86-64 và tại sao tôi không cần phải biên dịch với -fPIC trên trước đây?

+1

Tôi chưa bao giờ hiểu điều này. Nếu trình biên dịch có thể cho bạn biết chính xác tùy chọn nào sẽ sử dụng tự động, tại sao nó yêu cầu bạn nói từ ảo thuật để làm cho nó hoạt động chính xác? Grrr .. –

+0

@Billy Oneal, Bây giờ tôi tin rằng đó là trường hợp trừu tượng bị rò rỉ. Chúng khác nhau về cách chúng tải dữ liệu toàn cầu, ảnh hưởng đến việc liệu PIC có cần thiết hay không. –

+0

Tôi hiểu sự cần thiết cho sự khác biệt. Những gì tôi không hiểu là lý do tại sao bạn cần phải cung cấp cho trình biên dịch một chuyển đổi để làm cho nó làm điều đó. –

Trả lời

16

Tôi đã tìm thấy a nice and detailed explanation, mà nắm tới:

  1. x86-64 sử dụng IP tương đối bù đắp để tải dữ liệu toàn cầu, x86-32 không thể, vì vậy nó dereferences một toàn cầu bù đắp.
  2. bù đắp IP tương đối không hoạt động đối với thư viện được chia sẻ, vì biểu tượng toàn cục có thể bị ghi đè, do đó x86-64 bị hỏng khi không được xây dựng bằng PIC.
  3. Nếu x86-64 được tạo bằng PIC, điều kiện bù đắp tương đối IP hiện tại mang lại con trỏ đến mục nhập GOT, sau đó được bỏ qua.
  4. x86-32, tuy nhiên, đã sử dụng một tham số của khoản chênh lệch toàn cầu, vì vậy nó được chuyển thành mục nhập GOT trực tiếp.
4

Đây là vấn đề về mô hình mã. Theo mặc định, mã tĩnh được xây dựng giả sử toàn bộ chương trình sẽ ở trong phần 2G thấp hơn của không gian địa chỉ bộ nhớ. Mã cho các thư viện được chia sẻ cần phải được biên dịch cho một mô hình bộ nhớ khác, hoặc là PIC, hoặc với -mcmodel = large sẽ biên dịch mà không đưa ra giả định đó.

Lưu ý rằng -mcmodel = lớn không được triển khai trong phiên bản gcc cũ hơn (nó là 4.4, không phải là 4.2, tôi không biết 4.3). .

+0

Điều này có ý nghĩa - địa chỉ tuyệt đối 32 bit không thể được chuyển thành di chuyển tương đối, vì địa chỉ tải của thư viện có thể> 2GB. – caf

+0

Có, tôi hiểu rằng mã độc lập vị trí cần phải khác nhau trong việc tính toán độ lệch nhảy nhưng tôi cố gắng hiểu tại sao nó * hoạt động trên x86 * mà không có * '-fpic'. –

+0

@Alex, bộ tải động có thể xử lý một số nhưng không phải tất cả các bản ghi di dời và lý do mà một số bản ghi di chuyển không được xử lý là chúng giả định một tình huống không đúng. Chỉ có một mô hình bộ nhớ không phải là PIC 32 bit và mô hình đó chỉ sử dụng các bản ghi di dời được xử lý. Có một số mô hình bộ nhớ không PIC 64 bit, một số tương thích với việc di chuyển động, một số thì không. Nếu bạn sử dụng -mcmodel = large với gcc 4.4, bạn không cần -fpic. – AProgrammer

0

Đó hoàn toàn là một yêu cầu tùy ý mà người ABI đã áp đặt cho chúng tôi. Không có lý do hợp lý tại sao liên kết động trên x86_64 không thể hỗ trợ các thư viện non-PIC. Tuy nhiên, kể từ khi x86_64 không phải là dưới áp lực đăng ký khủng khiếp như x86 (và có tính năng tốt hơn cho PIC), tôi không biết của bất kỳ lý do quan trọng không sử dụng PIC.

+0

Ngoại trừ việc nó hỗ trợ các thư viện không phải PIC. Nó không hỗ trợ một số bản ghi di dời vì thường được tải theo cách mà các giả định được thực hiện bởi các bản ghi di dời này không hợp lệ, nhưng nếu bạn không sử dụng chúng, thì không có vấn đề gì. – AProgrammer

Các vấn đề liên quan