Có nghĩa là gì khi một hệ thống gọi tên nếu không thực hiện bằng ngôn ngữ lập trình?


14

Tôi muốn hiểu thuật ngữ "cuộc gọi hệ thống". Tôi quen thuộc rằng các cuộc gọi hệ thống được sử dụng để nhận các dịch vụ kernel từ một ứng dụng không gian người dùng.

Phần tôi cần làm rõ là sự khác biệt giữa "cuộc gọi hệ thống" và "C thực hiện cuộc gọi hệ thống".

Đây là một trích dẫn làm tôi bối rối:

Trên các hệ thống giống Unix, API đó thường là một phần của việc triển khai thư viện C (libc), như glibc, cung cấp các hàm bao bọc cho các cuộc gọi hệ thống, thường được đặt tên giống như các cuộc gọi hệ thống mà chúng gọi

"Các cuộc gọi hệ thống mà họ gọi" là gì? Nguồn của họ ở đâu? Tôi có thể bao gồm chúng trực tiếp trong mã của tôi?

Có phải "cuộc gọi hệ thống" theo nghĩa chung chỉ là giao diện được xác định POSIX nhưng để thực sự thấy việc triển khai, người ta có thể kiểm tra nguồn C và trong đó xem không gian người dùng thực sự đối với giao tiếp kernel thực sự diễn ra như thế nào?

Lưu ý cơ bản: Tôi đang cố gắng để hiểu, cuối cùng, mỗi chức năng c kết thúc tương tác với các thiết bị từ đó /dev.

Câu trả lời:


21

Các cuộc gọi hệ thống mỗi se là một khái niệm. Chúng đại diện cho các hành động mà các quá trình có thể yêu cầu kernel thực hiện.

Các cuộc gọi hệ thống đó được thực hiện trong nhân của hệ thống giống UNIX. Việc thực hiện này (được viết bằng C và bằng asm cho các phần nhỏ) thực sự thực hiện hành động trong hệ thống.

Sau đó, các quy trình sử dụng một giao diện để yêu cầu hệ thống thực hiện các cuộc gọi hệ thống. Giao diện này được chỉ định bởi POSIX. Đây là một tập hợp các chức năng của thư viện chuẩn C. Chúng thực sự là các hàm bao, chúng có thể thực hiện một số kiểm tra và sau đó gọi một hàm cụ thể của hệ thống trong kernel để bảo nó thực hiện các hành động theo yêu cầu của hệ thống. Và mẹo nhỏ là các chức năng đó là giao diện được đặt tên giống như hệ thống tự gọi và thường được gọi trực tiếp là "hệ thống gọi".

Bạn có thể gọi hàm trong kernel thực hiện cuộc gọi hệ thống trực tiếp thông qua cơ chế dành riêng cho hệ thống. Vấn đề là nó làm cho mã của bạn hoàn toàn không di động.

Vì vậy, một cuộc gọi hệ thống là:

  • một khái niệm, một chuỗi hành động được thực hiện bởi kernel để cung cấp dịch vụ cho tiến trình người dùng
  • chức năng của thư viện chuẩn C bạn nên sử dụng trong mã của mình để nhận dịch vụ này từ kernel.

1
Bạn có một ví dụ về "chức năng bao bọc" và một cuộc gọi hệ thống thực tế không? (đường dẫn tệp trong Linux hoặc liên kết đến các nguồn)
TheMeaningfulEngineer

3
Ví dụ: đây là việc thực hiện getpidlệnh gọi hệ thống trong nhân Linux: lxr.free-electrons.com/source/kernel/timer.c?v=2.6.35#L1337 . Và đây là chức năng trình bao bọc trong thư viện chuẩn GNU C glibc-2.19: fossies.org/dox/glibc-2.19/ .
lgeorget

@Igeorget: liên kết của bạn không còn hoạt động. Liên kết được cập nhật để triển khai kernel: github.com/torvalds/linux/blob/ . Tôi không thể tìm thấy những gì glibc làm những ngày này, mã đó là không thể điều hướng.
rchard2scout

6

Cuộc gọi hệ thống là một cách để yêu cầu hệ điều hành (kernel) của bạn thực hiện một số thao tác thay mặt cho chương trình của bạn, rằng chương trình không thể tự thực hiện (hoặc chỉ bất tiện). Lý do không thể thực hiện một số thao tác thông thường là cho phép một chương trình ngẫu nhiên thực hiện chúng có thể làm tổn hại đến tính toàn vẹn của hệ thống, như thực hiện I / O (trực tiếp vào RAM, ghi đè lên mọi thứ).

POSIX định nghĩa một giao diện cho các chương trình, một số chức năng nhất định mà chương trình của bạn có thể gọi. Một số trong số đó dịch ít nhiều trực tiếp đến các cuộc gọi hệ thống, một số khác đòi hỏi nhiều công phu hơn. Đó là thời gian chạy cho ngôn ngữ của bạn, ví dụ thư viện C, người chịu trách nhiệm cung cấp giao diện POSIX và đóng gói các đối số và nhận lại kết quả cho người gọi.

Các hệ thống Unixy cung cấp giao diện POSIX ít nhiều trực tiếp như các cuộc gọi hệ thống. Thông thường có một cách để gọi các cuộc gọi hệ thống trực tiếp, tìm kiếm syscall(2)các chi tiết về cách sử dụng thiết bị này trong Linux.


1
Bạn chạm vào một điểm quan trọng mà các câu trả lời khác chỉ cần chạm vào. Bất kỳ chức năng mà một lập trình viên có khả năng một cách hợp lý có thể viết cho mình (ví dụ như strlen, strcpy, sqrt, và qsort) có thể và có lẽ là trong không gian sử dụng, nạp từ thư viện. (Chủ yếu là libc; các hàm toán học như sqrtvà các hàm lượng giác và hyperbol có lẽ nằm trong libm, thư viện toán học.) ((Tiếp theo)
Scott

1
(tiếp theo) ... Nhưng không có cách nào người dùng có thể viết riêng của mình fork, killhoặc openchức năng, bởi vì các yêu cầu truy cập vào không gian hệ điều hành hạt nhân bộ nhớ (ví dụ, bảng tiến trình) hoặc hướng dẫn đặc quyền (ví dụ, I / O). Do đó, mã thực hiện các chức năng này phải nằm trong nhân hệ điều hành; do đó, chức năng hệ thống hoặc các cuộc gọi hệ thống.
Scott

5

Chắc chắn, chúng ta hãy làm như thế nào nhiều hướng-chúng ta có thể nhìn vào con voi này từ đâu? Điều.

Cuộc gọi hệ thống thực tế là, trong chương trình được xây dựng của bạn, lệnh máy kích hoạt sự leo thang đặc quyền vào chế độ kernel và trong chính kernel đó là mã mà lệnh đó gọi. Mã libc (và mọi thời gian chạy ngôn ngữ) thiết lập các thanh ghi máy và các tham số trong bộ lưu trữ nơi mã hạt nhân mong muốn tìm thấy chúng, có thể là các vị trí kỳ lạ do các ràng buộc đối với lệnh máy đó.

Khi đã ở trong mã hệ điều hành, có một chút hình ảnh phản chiếu của các công cụ cụ thể của máy mà thời gian chạy của người dùng đã thực hiện và sau đó là một cuộc gọi chương trình con hoàn toàn bình thường.
Nếu bạn muốn xem chính xác cách thức hoạt động của hệ điều hành quy mô đầy đủ này, hãy kéo nguồn kernel ( git clone https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/) và làm ví dụ git grep -i system\ call. Kéo nguồn glibc và làm tương tự.


Đúng, nhưng lục lọi trong Linux hoặc glibc là một chút về mặt nặng nề ...
vonbrand

3

Trong Linux, ít nhất cơ chế gọi hệ thống hoạt động theo hầu hết các kiến ​​trúc bằng cách đặt một số dữ liệu được định dạng cụ thể (thường là một loại cấu trúc c) trong một số thanh ghi hoặc địa chỉ bộ nhớ được xác định trước.

Tuy nhiên, vấn đề xảy ra trong thực tế là buộc CPU phải chuyển sang không gian kernel để nó có thể chạy mã hạt nhân đặc quyền để phục vụ cuộc gọi. Điều này được thực hiện bằng cách buộc một lỗi thuộc loại nào đó (lỗi bị chia cho 0, tràn không xác định hoặc segfault, v.v.) điều này buộc kernel phải thực thi để xử lý lỗi.

Thông thường, kernel xử lý các lỗi bằng cách giết tiến trình gây ra hoặc chạy trình xử lý do người dùng cung cấp. Tuy nhiên, trong trường hợp của một tòa nhà, thay vào đó, nó sẽ kiểm tra các thanh ghi và vị trí bộ nhớ được xác định trước và nếu chúng có chứa một yêu cầu tòa nhà, nó sẽ chạy bằng cách sử dụng dữ liệu do quá trình người dùng cung cấp trong cấu trúc trong bộ nhớ. Điều này thường phải được thực hiện với một số lắp ráp thủ công đặc biệt và để dễ dàng sử dụng tòa nhà cho người dùng, thư viện C của hệ thống phải bọc nó như một chức năng. Đối với giao diện cấp thấp hơn, vui lòng xem http://man7.org/linux/man-pages/man2/syscall.2.html để biết một số thông tin về cách các tòa nhà chọc trời hoạt động và cách bạn có thể gọi sau đó mà không cần trình bao bọc C.

Điều này được đưa ra một sự đơn giản hóa, nó không đúng trong tất cả các kiến ​​trúc (mips có một hướng dẫn tòa nhà đặc biệt) và không nhất thiết phải hoạt động giống nhau trên tất cả các hệ điều hành. Tuy nhiên, nếu bạn có bất kỳ ý kiến ​​hoặc câu hỏi xin vui lòng hỏi.

Sửa đổi: Lưu ý, liên quan đến nhận xét của bạn về những thứ trong / dev / đây thực sự là một giao diện cấp cao hơn cho kernel, không phải là giao diện thấp hơn. Các thiết bị này thực sự sử dụng (khoảng) 4 tòa nhà cao tầng bên dưới. Viết cho chúng giống như một tòa nhà viết, đọc một tòa nhà đọc, mở / đóng chúng tương đương với các tòa nhà mở và đóng và chạy một ioctl gây ra một tòa nhà ioctl đặc biệt mà bản thân nó là một giao diện để truy cập vào một trong nhiều ioctl của hệ thống các cuộc gọi (đặc biệt, thường là các cuộc gọi cụ thể của thiết bị với cách sử dụng quá hẹp để viết toàn bộ tòa nhà cho chúng).


1

Mỗi cuộc gọi hệ thống có một số nguyên liên quan. Số nguyên này là một hàm của giá trị trả về của lệnh gọi hệ thống, số lượng đối số cho lệnh gọi hệ thống và loại đối số. Số cuộc gọi hệ thống này không là gì ngoài phần bù vào vectơ gọi hệ thống toàn cầu, vectơ này chỉ có thể truy cập trong chế độ đặc quyền chứa con trỏ tới các trình xử lý thích hợp. Quá trình khi gọi một cuộc gọi hệ thống, một ngắt phần mềm (ngắt bẫy) sẽ được tạo ra, do đó một trình xử lý bẫy sẽ được chạy để xác định cuộc gọi hệ thống nào sẽ được gọi. Sau đó, kernel sẽ sao chép các đối số của lệnh gọi hệ thống được chuyển bởi người dùng trên ngăn xếp vào các thanh ghi bộ xử lý và sau khi hoàn thành dịch vụ được yêu cầu, dữ liệu sẽ được sao chép trở lại vào ngăn xếp từ các thanh ghi bộ xử lý. Đây là một trong những lý do tại sao có các đối số giới hạn đối với các cuộc gọi hệ thống,


Mỗi cuộc gọi (hoạt động) được xác định bên trong bởi một số, đúng. Nhưng số lượng phụ thuộc vào hoạt động , không phụ thuộc vào giá trị trả về cũng như số lượng đối số. Một lời giải thích về cách nó được sử dụng để làm việc từ userland trên x86 có ở đây
vonbrand
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.