Bagaimana shell menjalankan program?

11

Jika saya mengkompilasi sebuah program menggunakan gcc, dan mencoba menjalankannya dari bash shell, apa urutan langkah-langkah yang tepat diikuti oleh bash untuk menjalankannya?

Aku tahu fork(), execve(), loader, dynamic linker(dan hal-hal lain) yang terlibat, tetapi bisa seseorang memberikan urutan yang tepat dari langkah-langkah dan beberapa referensi bacaan yang cocok?

Edit:

Dari jawaban, sepertinya pertanyaan itu bisa menyiratkan banyak kemungkinan. Saya ingin mempersempit kasus sederhana:

(test.c hanya mencetak hello world)

$ gcc test.c -o test
$ ./test

Apa yang akan menjadi langkah-langkah dalam kasus di atas ( ./test), khususnya yang terkait dengan program awal bash dalam beberapa proses anak, melakukan pemuatan, menautkan dll.?

Jake
sumber
4
Saya mengundang Anda untuk membaca lwn.net/Articles/630727
cuonglm
3
Mengapa tidak mencoba `strace bash -c 'test'?
Sergiy Kolodyazhnyy
2
Sepertinya buku teks Sistem Operasi yang layak akan menjadi sumber yang bagus untuk OP. Mencoba mempelajari cara kerja sistem operasi dengan mengajukan pertanyaan individual seperti ini sepertinya bukan merupakan proses yang produktif.
Barmar
Akan bermanfaat untuk melihat contoh minimal dari shell: brennan.io/2015/01/16/write-a-shell-in-c
jinawee

Jawaban:

5

Nah, urutan yang tepat dapat bervariasi, karena mungkin ada alias shell atau fungsi yang pertama kali diperluas / ditafsirkan sebelum program yang sebenarnya dijalankan, dan kemudian perbedaan untuk nama file yang memenuhi syarat ( /usr/libexec/foo) versus sesuatu yang akan dicari melalui semua direktori dari PATHvariabel lingkungan (adil foo). Juga, rincian eksekusi dapat memperumit masalah, karena foo | bar | zotmembutuhkan lebih banyak pekerjaan untuk shell (beberapa jumlah fork(2), dup(2)dan, tentu saja, pipe(2)antara panggilan sistem lainnya), sedangkan sesuatu seperti exec fooini jauh lebih sedikit bekerja sebagai shell hanya menggantikan dirinya dengan program baru (yaitu, tidak fork). Juga penting adalah kelompok proses (terutama kelompok proses latar depan, semua PID yang makanSIGINTketika seseorang mulai menumbuk pada Ctrl+ C, sesi, dan apakah pekerjaan akan dijalankan di latar belakang, dipantau ( foo &) atau latar belakang, diabaikan ( foo & disown). Rincian pengalihan I / O juga akan mengubah hal-hal, misalnya, jika input standar ditutup oleh shell ( foo <&-), atau apakah file dibuka sebagai stdin ( foo < blah).

straceatau yang serupa akan memberi informasi tentang panggilan sistem tertentu yang dibuat sepanjang proses ini, dan harus ada halaman manual untuk masing-masing panggilan itu. Pembacaan tingkat sistem yang sesuai adalah sejumlah bab dari "Programming Lanjutan di Lingkungan UNIX" dari Stevens, sementara buku shell (mis., "Dari Bash ke Z Shell") akan membahas sisi sisi hal-hal dengan lebih terinci.

thrig
sumber
Saya mengedit pertanyaan untuk mempersempit kasus sederhana
Jake
1

Dengan asumsi shell contoh buku teks (untuk kejelasan kode) yang sudah berjalan (sehingga penghubung dinamis selesai), perintah yang Anda sebutkan akan membutuhkan shell untuk melakukan panggilan sistem berikut:

  • baca: dapatkan perintah selanjutnya dalam hal ini gcc
  • garpu: diperlukan dua proses, kita asumsikan orang tua memiliki pid 500 dan anak untuk ilustrasi.
  • orang tua akan memanggil tunggu (501), sementara itu anak akan memanggil exec. Pada titik ini shell tidak lagi berjalan pada pid 501. gcc membuat banyak panggilan sistem termasuk membuka, menutup, membaca, menulis, chmod, fork, exec, menunggu dan keluar secara minimum.
  • ketika panggilan gcc keluar, tunggu akan kembali, tulis dipanggil untuk menampilkan prompt dan proses akan ulangi.

Perintah yang lebih rumit tentu saja menambah kerumitan pada urutan dasar ini. Dua contoh sederhana dari komplikasi dasar adalah pengalihan dasar di mana urutan buka, tutup, dup disisipkan di antara garpu dan exec dan proses latar belakang di mana menunggu dilewati (dan menunggu lain ditambahkan ke penangan sigchld).

Hildred
sumber
Tambahan kecil: pertanyaan yang diajukan tentang memuat dan menghubungkan dinamis. Semua kode yang terhubung secara statis, yaitu benar-benar termasuk dalam file program, dilakukan oleh kernel sebelum program dimulai. Pustaka yang dimuat secara dinamis, yaitu file terpisah, ditangani oleh program itu sendiri sebelum memulai main (). Kode untuk ini ditambahkan secara otomatis oleh gcc.
Stig Hemmer