Runtime etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Runtime etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

15 Ağustos 2017 Salı

Main metodu

Not :  Konu ile ilgili Komut Satırı Parse Etme başlıklı yazıya göz atabilirsiniz.

Windows GUI
Windows GUI uygulamaları WinMain ile başlarlar


Main metodu
Hangi programlama dili olursa (C, C++, Java) derlediğimiz program çalışmaya başlamadan önce - yani main metodumuzdan önce - kullandığımız dile ait runtime kütüphanesi bazı hazırlıklar yapar.

Örneğin Windows üzerindeki C runtime kütüphanesi _mainCRTStartup gibi fonksiyonları çağırır. Böylece main metodumuz uygulamamıza geçilen argümanlar parse edilmiş olarak başlayabilir. Açıklaması şöyle
The Visual Studio linker looks for int mainCRTStartup(void); and uses that, unless you specify another entry point with /ENTRY. The default implementation of mainCRTStartup calls GetCommandLine() to fill in argv[] before calling main(argc,argv). There are also other things in mainCRTStartup which you might want to happen: run global ctors, initialize the CRT state, ...

Dönen Metod Değeri
posix
main dönebilir. int'in değeri POSIX platformlarında 8 bit büyüklüğündedir. Yani 0-255 arasıdır.
Şöyle bir program olsun.
int main()
{
    return -1;
}
Linux'ta bunu çalıştırırsak
echo $?
Çıktı olarak şunu görürüz.
255
windows
Windows'ta 32 bit sayılar döndürülebiliyor. 64 bit sayı dönmüyor ancak zaten lazım da değil.

C++
Main Metodu yazısına taşıdım.

Parametreler
Parametreler Address Space Layout Randomization ile bellekte rastgele bir yere yerleştirilir. Açıklaması şöyle
When the kernel executes a process, it copies the command line arguments to read-write memory belonging to the process (on the stack, at least on Linux). The process can write to that memory like any other memory. When ps displays the argument, it reads back whatever is stored at that particular address in the process's memory. Most programs keep the original arguments, but it's possible to change them.
Bu parametreler değişitirilebilir. ps metodunun açıklaması şöyle
It is unspecified whether the string represented is a version of the argument list as it was passed to the command when it started, or is a version of the arguments as they may have been modified by the application. Applications cannot depend on being able to modify their argument list and having that modification be reflected in the output of ps.
Parametreleri değiştirmek için şöyle yaparız.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
  int i;
  
  for (i = 0; i < argc; i++)
  {
    memset(argv[i], '0' + (i % 10), strlen(argv[i]));
  }
  return 0;
}
Eğer main metodu parametre alıyorsa sonuncu parametreden sonraki şey NULL olmalıdır. Bu NULL olma kuralı ilk K&R 1978 kitabında yok daha sonradan eklenmiş.
argv[argc] is required to be a null pointer
Ne kadar büyüklükte argv girilebileceği ise işletim sistemi ayarlarından var. Eğer kısıtı aşarsak
"Argument list too long" şeklinde bir hata alırız.

Main'in Döndürdüğü Parametre
Main int döner. int[] dönemez. Standart döndürülebilen parametre değeri olarak sadece EXIT_SUCCESS (0) ve EXIT_FAILURE (1) değerlerini tanımlar.

Main'den Önce Çağrılabilecek Metodlar
GNU Runtime - Main'den Önce Çağrılabilecek Metodlar yazısına taşıdım.

Main ve .so Dosyası
Bir .so dosyasına main metodu eklenebiliyor. Böylece .so dosyası çalıştırılıp versiyon bilgisi ekrana bastırılabiliyor. Örneğin şu komut çalıştırılabiliyor.
$ /lib/x86_64-linux-gnu/libc.so.6
Derlerken sanırım -pie seçeneğini kullanmak gerekiyor

Main'den Main Çağırma
İnanması ve düşünmesi güç ama C'de bu yapılabiliyor. Örnekte stdin'den okunan veriyi stdout'a tersine yazan program var ve main'den main'i çağırarak yapıyor.
main(c){if(c=getchar(),c>=0)main(),putchar(c);}

Aynı şeyi Java'da da yapmak mümkün. Örnekte exception yiyen bir program tekrar başlatılıyor.
public static void main(String[] args) {
    try {
        //something wrong happens here
    }catch(Throwable e) {
        e.printStackTrace();
        main(args);
    }
}
Java
Main Metodu yazısına taşıdım.
C#
main metodu void veya int dönebilir.

.Net
.Net assemblylerinin entry metodu EntryPoint ile alınabilir.


23 Ocak 2017 Pazartesi

exec ailesi

Not : fork() sistem çağrısı başlıklı yazıda std::system() çağrısının altta execl sistem çağrısını kullandığını görebilirsiniz.

Not 2: Windows'ta C kütüphanesinden _spawn, _wspawn ailesine ait metodlar exec ailesine çok benziyor.

exec sistem çağrısı ailesi
exec ailesindeli metodlar şöyle. v ile bitenler çalıştırılacak uygulamaya geçilecek parametreleri bir char dizisi ile alıyorlar. l ile bitenler ise parametreleri variable argument list olarak alıyorlar.
execl
execle
execlp
execv
execve
execvp
Aşağıdaki şekli buradan aldım. Şekilde execlp ve execvp'nin çalıştırılmak istenen uygulamayı $PATH ortam değişkeni altında arayacağı görülebilir.


execl
execl metodu yazısına taşıdım.

execle
Örnek ver

execlp
Çalıştırılmak istenen uygulam $PATH dizininde olmalıdır. Şöyle yaparız.
std::string str("...");
execlp("curl", "-b", "cookie.txt", "-d", str.c_str());

execv
execv metodu yazısına taşıdım.

execve
execve yazısına taşıdım.

execvpe
execvpe Linux üzerinde bulunuyor ancak standart bir metod değil.

execvp - Programı path içinde arar
Şu satırın dahil edilmesi gerekir.
#include <unistd.h>
Metodun imzası şöyle
int execvp(const char *file, char *const argv[]);
argv bir char* array. Son elemanının null olması gerekiyor.  C tarzı programlarda şöyle yaparız. Önce parametre dizisini doldururuz.
// The argument list to pass to the “ls” command.
 char* arg_list[] = { 
   “-l”, 
    “/”,
    NULL // The argument list must end with a NULL
  };
Daha sonra execvp'yi çağırırız.
execvp ("ls", arg_list);
C++ ile parametrelerin büyüklüğünü tam bilmediğimiz bir argv dizisini oluşturmak için bir yöntem şöyle
// given:
std::vector<std::string> args = the_args();
std::vector<char*> argv(args.size() + 1);
std::transform(args.begin(), args.end(), argv.begin(),
  [](std::string& s) { return const_cast<char*>(s.c_str()); });

int error = execvp(path, argv.data());
exec ailesi ve threadler
exec ailesinden bir metod çalıştırılınca eski uygulamadaki exec() metodunu çağıran thread hariç geri kalan tüm threaler kapatılır. man exec sayfasında şu yazıyor.
All threads other than the calling thread are destroyed during an execve().
Bir sınav sorusu şöyle
What happens to the other threads, if one of many threads within a process makes an exec() call? Why?
Cevabı ise şöyle
A call to any exec function from a process with more than one thread shall result in all threads being terminated and the new executable image being loaded and executed. No destructor functions or cleanup handlers shall be called.
Yani exec(...) çağrısından sonra tek bir thread yaşamaya devam ediyor.

exec ailesi ve sinyaller
Set ignored signals to SIG_DFL before execvp() sorusunda da anlatıldığı gibi yeni açılan uygulama eski uygulamadaki dikkate alınmayan sinyalleri dikkate almıyor. Ancak eski uygulamadaki atanmış sinyalleri SIG_DFL olarak atıyor. Yani default handler'ı geri atıyor.


exec ailesi ve programı çıktısı
Bu konudaki en önemli doküman Process sınıfındaki açıklama.Yani çıktısı olan programların çıktılarını okumakta fayda var.