aboutsummaryrefslogtreecommitdiff
path: root/winsup/cygwin/dll_init.h
blob: 62739f729a676f2ae269fef79f1fe7cddebe3349 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/* dll_init.h

This file is part of Cygwin.

This software is a copyrighted work licensed under the terms of the
Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
details. */

struct per_module
{
#ifdef __i386__
  char ***envptr;
#endif
  void (**ctors)(void);
  void (**dtors)(void);
  void *data_start;
  void *data_end;
  void *bss_start;
  void *bss_end;
  int (*main)(int, char **, char **);
  per_module &operator = (per_process *p)
  {
#ifdef __i386__
    envptr = p->envptr;
#endif
    ctors = p->ctors;
    dtors = p->dtors;
    data_start = p->data_start;
    data_end = p->data_end;
    bss_start = p->bss_start;
    bss_end = p->bss_end;
    main = p->main;
    return *this;
  }
  void run_ctors ();
  void run_dtors ();
};


typedef enum
{
  DLL_NONE,
  DLL_SELF, /* main-program.exe, cygwin1.dll */
  DLL_LINK,
  DLL_LOAD,
  DLL_ANY
} dll_type;

struct dll
{
  struct dll *next, *prev;
  per_module p;
  HMODULE handle;
  int count;
  bool has_dtors;
  dll_type type;
  long ndeps;
  dll** deps;
  DWORD image_size;
  void* preferred_base;
  PWCHAR modname;
  FILE_BASIC_INFORMATION fbi;
  FILE_INTERNAL_INFORMATION fii;
  PWCHAR forkable_ntname;
  WCHAR ntname[1]; /* must be the last data member */

  void detach ();
  int init ();
  void nominate_forkable (PCWCHAR);
  bool create_forkable ();
  void run_dtors ()
  {
    if (has_dtors)
      {
	has_dtors = 0;
	p.run_dtors ();
      }
  }
};

#define MAX_DLL_BEFORE_INIT     100

class dll_list
{
  /* forkables */
  enum
    {
      forkables_unknown,
      forkables_impossible,
      forkables_disabled,
      forkables_needless,
      forkables_needed,
      forkables_created,
    }
    forkables_needs;
  DWORD forkables_dirx_size;
  PWCHAR forkables_dirx_ntname;
  PWCHAR forkables_mutex_name;
  HANDLE forkables_mutex;
  void track_self ();
  size_t forkable_ntnamesize (dll_type, PCWCHAR fullntname, PCWCHAR modname);
  void prepare_forkables_nomination ();
  void update_forkables_needs ();
  bool update_forkables ();
  bool create_forkables ();
  void denominate_forkables ();
  bool close_mutex ();
  void try_remove_forkables (PWCHAR dirbuf, size_t dirlen, size_t dirbufsize);
  void set_forkables_inheritance (bool);
  void request_forkables ();

  dll *end;
  dll *hold;
  dll_type hold_type;
  static muto protect;
  /* Use this buffer under loader lock conditions only. */
  static WCHAR NO_COPY nt_max_path_buffer[NT_MAX_PATH];
public:
  static HANDLE ntopenfile (PCWCHAR ntname, NTSTATUS *pstatus = NULL,
			    ULONG openopts = 0, ACCESS_MASK access = 0,
			    HANDLE rootDir = NULL);
  static bool read_fii (HANDLE fh, PFILE_INTERNAL_INFORMATION pfii);
  static bool read_fbi (HANDLE fh, PFILE_BASIC_INFORMATION pfbi);
  static PWCHAR form_ntname (PWCHAR ntbuf, size_t bufsize, PCWCHAR name);
  static PWCHAR form_shortname (PWCHAR shortbuf, size_t bufsize, PCWCHAR name);
  static PWCHAR nt_max_path_buf ()
  {
    return nt_max_path_buffer;
  }
  static PCWCHAR buffered_shortname (PCWCHAR name)
  {
    form_shortname (nt_max_path_buffer, NT_MAX_PATH, name);
    return nt_max_path_buffer;
  }

  dll *main_executable;
  dll start;
  int loaded_dlls;
  int reload_on_fork;
  dll *operator [] (PCWCHAR ntname);
  dll *alloc (HINSTANCE, per_process *, dll_type);
  dll *find (void *);
  void detach (void *);
  void init ();
  void load_after_fork (HANDLE);
  void reserve_space ();
  void load_after_fork_impl (HANDLE, dll* which, int retries);
  dll *find_by_modname (PCWCHAR modname);
  void populate_deps (dll* d);
  void topsort ();
  void topsort_visit (dll* d, bool goto_tail);
  void append (dll* d);

  void release_forkables ();
  void cleanup_forkables ();
  bool setup_forkables (bool with_forkables)
  {
    if (forkables_needs == forkables_impossible)
      return true; /* short cut to not retry fork */
    /* Once used, always use forkables in current process chain. */
    if (forkables_needs != forkables_unknown)
      with_forkables = true;
    if (with_forkables)
      request_forkables ();
    return with_forkables;
  }

  dll *inext ()
  {
    while ((hold = hold->next))
      if (hold_type == DLL_ANY || hold->type == hold_type)
	break;
    return hold;
  }

  dll *istart (dll_type t)
  {
    hold_type = t;
    hold = &start;
    return inext ();
  }
  void guard(bool lockit)
  {
    if (lockit)
      protect.acquire ();
    else
      protect.release ();
  }
  friend void dll_global_dtors ();
  dll_list () { protect.init ("dll_list"); }
};

/* References:
   http://msdn.microsoft.com/en-us/windows/hardware/gg463125
   http://msdn.microsoft.com/en-us/library/ms809762.aspx
*/
struct pefile
{
  IMAGE_DOS_HEADER dos_hdr;

  char* rva (ptrdiff_t offset) { return (char*) this + offset; }
  PIMAGE_NT_HEADERS pe_hdr () { return (PIMAGE_NT_HEADERS) rva (dos_hdr.e_lfanew); }
  PIMAGE_OPTIONAL_HEADER optional_hdr () { return &pe_hdr ()->OptionalHeader; }
  PIMAGE_DATA_DIRECTORY idata_dir (DWORD which)
  {
    PIMAGE_OPTIONAL_HEADER oh = optional_hdr ();
    return (which < oh->NumberOfRvaAndSizes)? oh->DataDirectory + which : 0;
  }
};

extern dll_list dlls;
void dll_global_dtors ();

/* These probably belong in a newlib header but we can keep them here
   for now.  */
extern "C" int __cxa_atexit(void (*)(void*), void*, void*);
extern "C" int __cxa_finalize(void*);