Tại sao tất cả các vị trí biên dịch mã không độc lập?


85

Khi biên dịch các thư viện được chia sẻ trong gcc, tùy chọn -fPIC sẽ biên dịch mã dưới dạng độc lập về vị trí. Có bất kỳ lý do nào (hiệu suất hoặc cách khác) tại sao bạn không biên dịch tất cả các vị trí mã độc lập?


2
Nhưng wowest là không hoàn toàn chính xác. Nhiều lệnh gọi và bước nhảy sử dụng bước nhảy tương đối để chúng thậm chí không cần bảng nhảy sau khi được di chuyển xung quanh.
Không xác định

Nhìn vào mã lắp ráp được tạo, nó có vẻ như địa chỉ của hàm được tải khi không có mã fpic, nó xuất hiện đơn giản là một bước nhảy. Tôi đang hiểu sai câu nói của bạn?
ojblass

@ojblass ý tôi là một số bước nhảy giống như "nhảy 50 hướng dẫn về phía trước ở đây" hoặc "nhảy 5 hướng dẫn về phía sau" thay vì "nhảy tới 0x400000". Vì vậy, để nói rằng bạn phải tải một địa chỉ mọi lúc với -fPIC là không hoàn toàn đúng.
Không xác định

Bài viết trên Wikipedia cung cấp một mô tả tốt. Về cơ bản, trên một số kiến ​​trúc không có cách trực tiếp để chuyển đến một địa chỉ tương đối. Do đó, PIC đắt hơn để sử dụng trên những cung đó. Xem câu trả lời của @ EvanTeran để biết thêm thông tin.
Alexei Sholik

Câu trả lời:


67

Nó thêm một hướng dẫn. Với mã vị trí độc lập, bạn phải tải địa chỉ của hàm của bạn và sau đó chuyển đến nó. Thông thường, địa chỉ của hàm đã có trong dòng lệnh.


33

Bài viết này giải thích cách thức hoạt động của PIC và so sánh nó với giải pháp thay thế - di dời thời gian tải . Tôi nghĩ nó có liên quan đến câu hỏi của bạn.


16
@Nick: Tôi không đồng ý. Nếu nó giúp người hỏi, đó là một câu trả lời. Chỉ vào một hoặc hai bài báo có liên quan có thể cung cấp nhiều thông tin.
Eli Bendersky

5
Không có kết luận trong bài đăng này, chỉ là một liên kết đến một bài báo. Thậm chí không có manh mối nào cho thấy PIC không được sử dụng theo mặc định vì các vấn đề về hiệu suất.
Nick,

10
Mặc dù liên kết này có thể trả lời câu hỏi, nhưng tốt hơn hết bạn nên đưa các phần thiết yếu của câu trả lời vào đây và cung cấp liên kết để tham khảo. Các câu trả lời chỉ có liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi.
Rob

4
@Rob: điều hữu ích sẽ là đề xuất chỉnh sửa và không sử dụng nhận xét để than vãn. Câu trả lời này là 4 năm tuổi. Trở lại sau đó SO có quy tắc ít nghiêm ngặt về một câu trả lời nên xem xét như thế nào
Eli Bendersky

6
Bài đăng này hiển thị dưới "xem xét" yêu cầu tôi làm như vậy và tôi đã làm. Ai đó đã gắn cờ nó. "Bình luận than vãn" là tự động sản xuất bởi SO, không phải tôi.
Rob

27

Có, có lý do hiệu suất. Một số truy cập có hiệu quả nằm dưới một lớp định hướng khác để có được vị trí tuyệt đối trong bộ nhớ.

Ngoài ra còn có GOT (Bảng bù toàn cục) lưu trữ hiệu số của các biến toàn cục. Đối với tôi, đây chỉ giống như một bảng sửa lỗi IAT, được phân loại là phụ thuộc vào vị trí theo wikipedia và một số nguồn khác.

http://en.wikipedia.org/wiki/Position_independent_code


23

Ngoài câu trả lời được chấp nhận. Một điều làm ảnh hưởng đến hiệu suất mã PIC là thiếu "địa chỉ IP tương đối" trên x86. Với "địa chỉ IP tương đối", bạn có thể yêu cầu dữ liệu là X byte từ con trỏ hướng dẫn hiện tại. Điều này sẽ làm cho mã PIC đơn giản hơn rất nhiều.

Các bước nhảy và cuộc gọi, thường là EIP tương đối, vì vậy chúng không thực sự gây ra vấn đề. Tuy nhiên, việc truy cập dữ liệu sẽ cần thêm một chút thủ thuật. Đôi khi, một thanh ghi sẽ được bảo lưu tạm thời như một "con trỏ cơ sở" tới dữ liệu mà mã yêu cầu. Ví dụ, một kỹ thuật phổ biến là lạm dụng cách gọi hoạt động trên x86:

call label_1
.dd 0xdeadbeef
.dd 0xfeedf00d
.dd 0x11223344
label_1:
pop ebp            ; now ebp holds the address of the first dataword
                   ; this works because the call pushes the **next**
                   ; instructions address
                   ; real code follows
mov eax, [ebp + 4] ; for example i'm accessing the '0xfeedf00d' in a PIC way

Kỹ thuật này và các kỹ thuật khác thêm một lớp chuyển hướng vào các truy cập dữ liệu. Ví dụ, GOT (Bảng bù toàn cục) được sử dụng bởi trình biên dịch gcc.

x86-64 đã thêm chế độ "RIP tương đối" giúp mọi thứ đơn giản hơn rất nhiều .


1
IIRC MIPS cũng không có địa chỉ tương đối với PC, ngoại trừ các bước nhảy tương đối
phuclv

1
Đây là một kỹ thuật phổ biến được sử dụng trong shellcode để lấy địa chỉ mà nó đang thực thi. Tôi đã sử dụng điều này trong một số giải pháp CTF.
sherrellbc

2

Bởi vì việc triển khai mã hoàn toàn độc lập về vị trí sẽ thêm một ràng buộc vào trình tạo mã, điều này có thể ngăn việc sử dụng các hoạt động nhanh hơn hoặc thêm các bước bổ sung để bảo toàn ràng buộc đó.

Đây có thể là một sự đánh đổi có thể chấp nhận được để có được đa xử lý mà không cần hệ thống bộ nhớ ảo, nơi bạn tin tưởng các quá trình không xâm phạm bộ nhớ của nhau và có thể cần tải một ứng dụng cụ thể tại bất kỳ địa chỉ cơ sở nào.

Trong nhiều hệ thống hiện đại, sự cân bằng hiệu suất là khác nhau và bộ tải định vị lại thường ít tốn kém hơn (tốn bất kỳ thời gian nào mã được tải lần đầu tiên) so với điều tốt nhất mà trình tối ưu hóa có thể làm nếu nó có quyền thống trị tự do. Ngoài ra, sự sẵn có của không gian địa chỉ ảo ẩn phần lớn động lực cho sự độc lập về vị trí ngay từ đầu.


1

Ngoài ra, phần cứng bộ nhớ ảo trong hầu hết các bộ vi xử lý hiện đại (được hầu hết các hệ điều hành hiện đại sử dụng) có nghĩa là rất nhiều mã (tất cả các ứng dụng không gian người dùng, cấm sử dụng mmap kỳ quặc hoặc tương tự) không cần phải độc lập về vị trí. Mọi chương trình đều có không gian địa chỉ riêng mà nó cho rằng bắt đầu từ 0.


4
Nhưng ngay cả với mã VM-MMU PIC cũng cần thiết để đảm bảo rằng cùng một thư viện .so chỉ được tải một lần vào bộ nhớ khi nó được sử dụng bởi các tệp thực thi khác nhau.
mmmmmmmm

1

position-independent code có chi phí hiệu suất trên hầu hết các kiến ​​trúc, vì nó yêu cầu thêm một thanh ghi.

Vì vậy, đây là cho mục đích hiệu suất.


0

Ngày nay hệ điều hành và trình biên dịch theo mặc định làm cho tất cả mã dưới dạng mã độc lập về vị trí. Hãy thử biên dịch mà không có cờ -fPIC, mã sẽ biên dịch tốt nhưng bạn sẽ chỉ nhận được một cảnh báo. Giống như các cửa sổ của hệ điều hànhOS sử dụng một kỹ thuật được gọi là ánh xạ bộ nhớ để đạt được điều này.


-5

Câu hỏi bắt đầu từ năm 2009. Mười năm đã trôi qua, và bây giờ tất cả các mã thực sự là độc lập về vị trí. Điều đó hiện được thực thi bởi hệ điều hành và trình biên dịch. Không có cách nào để chọn không tham gia. Tất cả mã được biên dịch bắt buộc bằng PIE và cờ -no-pic / -no-pie đang bị bỏ qua, như một phần của lý do ASLR này. Lý do là để làm chậm các ứng dụng nhanh trước đây và bán phần cứng mới hơn, dưới chiêu bài tăng cường bảo mật. Điều đó là hoàn toàn không hợp lý, bởi vì hiện nay kích thước bộ nhớ lớn cho phép chúng ta thoát khỏi địa ngục của liên kết động, biên dịch tất cả các ứng dụng một cách tĩnh.

Điều tương tự đã xảy ra trước đây, khi mọi người im lặng chấp nhận chế độ thực và các quyền tự do khác đang bị tước đoạt. Và tôi phiền bạn, MMU bị chậm nặng do chuyển đổi ngữ cảnh và độ trễ dịch địa chỉ. Bạn sẽ không tìm thấy MMU trong các hệ thống quan trọng về hiệu suất, giống như những hệ thống được các nhà khoa học sử dụng để lấy mẫu thí nghiệm vật lý.

Bạn không phàn nàn, bởi vì bạn thậm chí không biết rằng mã của bạn đang bị hạn chế bởi tất cả các bánh xe đào tạo này. Tôi có thể nói gì? Tận hưởng phần mềm chậm hơn 2 lần với PIC của họ ngay bây giờ! Hơn nữa, với sự ra đời của LLVM, sẽ sớm có JIT (mã được quản lý) được thực thi, không có quyền truy cập vào cấu trúc nội tuyến x86, điều này sẽ tiếp tục làm chậm bất kỳ mã C / C ++ nào. "Những người hy sinh tự do vì an ninh cũng không xứng đáng."


Đó chỉ là một tuyên bố về sự thật: 10 năm trước PIC là tùy chọn, nhưng ngày nay nó là mặc định và bắt buộc. Tôi nghi ngờ mã không phải PIE sẽ được hỗ trợ trong các bản phát hành hệ điều hành tiếp theo. Giống như hỗ trợ chế độ thực đã bị loại bỏ sau Windows 9x. Vì vậy, câu hỏi sử dụng hay không sử dụng PIC trở thành một chủ đề khoa học máy tính lý thuyết nhiều hơn, trừ khi bạn bằng cách nào đó mở khóa hệ điều hành của mình và kích hoạt lại hỗ trợ cho nó. Điều quan trọng nhất mà mọi người cần biết về PIC là nó đủ chậm để các trình biên dịch cho đến nay đã hỗ trợ biên dịch tĩnh và đã có các phiên bản tĩnh của hầu hết các DLL.
SmugLispWeenie

1
Một vài câu đầu tiên của bạn chỉ là một tuyên bố về sự kiện. Phần còn lại là ý kiến, giáp ranh với âm mưu.
Mitch Lindgren

Vâng, chỉ nói chuyện với mọi người, hỏi ý kiến ​​của họ về nó. Cá nhân tôi thấy rằng PIC và không phải PIC cũng trở thành một câu hỏi về hệ tư tưởng. PIC là chương trình tương đương với chủ nghĩa Cộng sản, nơi mã được sản xuất hàng loạt và mọi người đều nhận được cùng một bản sao. Non-PIC là một chương trình tương đương với Chủ nghĩa tư bản, nơi có nhiều phiên bản cạnh tranh của cùng một mã. Vì vậy, những người có tư tưởng cánh tả hơn trong tiềm thức ủng hộ PIC để chứng minh quan điểm rằng hệ tư tưởng yêu thích của họ có thể hoạt động ít nhất trong lĩnh vực máy tính. Cũng chính những người này sẽ khuyên bạn không nên nói bằng cách sử dụng libpng được sửa đổi cá nhân.
SmugLispWeenie

2
Chúng tôi có thể không có những lời dị nghị chính trị trên một trang web lập trình được không, xin cảm ơn bạn
Ryan McCampbell
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.