- split logoff and shutdown resources
[reactos.git] / reactos / ntoskrnl / mm / elf.inc.h
1 /* $Id$
2 */
3 #include <ntoskrnl.h>
4
5 #define NDEBUG
6 #include <internal/debug.h>
7
8 #include <reactos/exeformat.h>
9
10 #ifndef __ELF_WORD_SIZE
11 #error __ELF_WORD_SIZE must be defined
12 #endif
13
14 #ifndef MAXULONG
15 #define MAXULONG ((ULONG)(~1))
16 #endif
17
18 #include <elf/elf.h>
19
20 /* TODO: Intsafe should be made into a library, as it's generally useful */
21 static __inline BOOLEAN Intsafe_CanAddULongPtr
22 (
23 IN ULONG_PTR Addend1,
24 IN ULONG_PTR Addend2
25 )
26 {
27 return Addend1 <= (MAXULONG_PTR - Addend2);
28 }
29
30 #define Intsafe_CanAddSizeT Intsafe_CanAddULongPtr
31
32 static __inline BOOLEAN Intsafe_CanAddULong32
33 (
34 IN ULONG Addend1,
35 IN ULONG Addend2
36 )
37 {
38 return Addend1 <= (MAXULONG - Addend2);
39 }
40
41 static __inline BOOLEAN Intsafe_AddULong32
42 (
43 OUT PULONG32 Result,
44 IN ULONG Addend1,
45 IN ULONG Addend2
46 )
47 {
48 if(!Intsafe_CanAddULong32(Addend1, Addend2))
49 return FALSE;
50
51 *Result = Addend1 + Addend2;
52 return TRUE;
53 }
54
55 static __inline BOOLEAN Intsafe_CanAddULong64
56 (
57 IN ULONG64 Addend1,
58 IN ULONG64 Addend2
59 )
60 {
61 return Addend1 <= (((ULONG64)-1) - Addend2);
62 }
63
64 static __inline BOOLEAN Intsafe_AddULong64
65 (
66 OUT PULONG64 Result,
67 IN ULONG64 Addend1,
68 IN ULONG64 Addend2
69 )
70 {
71 if(!Intsafe_CanAddULong64(Addend1, Addend2))
72 return FALSE;
73
74 *Result = Addend1 + Addend2;
75 return TRUE;
76 }
77
78 static __inline BOOLEAN Intsafe_CanMulULong32
79 (
80 IN ULONG Factor1,
81 IN ULONG Factor2
82 )
83 {
84 return Factor1 <= (MAXULONG / Factor2);
85 }
86
87 static __inline BOOLEAN Intsafe_MulULong32
88 (
89 OUT PULONG32 Result,
90 IN ULONG Factor1,
91 IN ULONG Factor2
92 )
93 {
94 if(!Intsafe_CanMulULong32(Factor1, Factor2))
95 return FALSE;
96
97 *Result = Factor1 * Factor2;
98 return TRUE;
99 }
100
101 static __inline BOOLEAN Intsafe_CanOffsetPointer
102 (
103 IN CONST VOID * Pointer,
104 IN SIZE_T Offset
105 )
106 {
107 /* FIXME: (PVOID)MAXULONG_PTR isn't necessarily a valid address */
108 return Intsafe_CanAddULongPtr((ULONG_PTR)Pointer, Offset);
109 }
110
111 #if __ELF_WORD_SIZE == 32
112 #define ElfFmtpAddSize Intsafe_AddULong32
113 #define ElfFmtpReadAddr ElfFmtpReadULong
114 #define ElfFmtpReadOff ElfFmtpReadULong
115 #define ElfFmtpSafeReadAddr ElfFmtpSafeReadULong
116 #define ElfFmtpSafeReadOff ElfFmtpSafeReadULong
117 #define ElfFmtpSafeReadSize ElfFmtpSafeReadULong
118 #elif __ELF_WORD_SIZE == 64
119 #define ElfFmtpAddSize Intsafe_AddULong64
120 #define ElfFmtpReadAddr ElfFmtpReadULong64
121 #define ElfFmtpReadOff ElfFmtpReadULong64
122 #define ElfFmtpSafeReadAddr ElfFmtpSafeReadULong64
123 #define ElfFmtpSafeReadOff ElfFmtpSafeReadULong64
124 #define ElfFmtpSafeReadSize ElfFmtpSafeReadULong64
125 #endif
126
127 /* TODO: these are standard DDK/PSDK macros */
128 #define RtlRetrieveUlonglong(DST_, SRC_) \
129 (RtlCopyMemory((DST_), (SRC_), sizeof(ULONG64)))
130
131 #ifndef RTL_FIELD_SIZE
132 #define RTL_FIELD_SIZE(TYPE_, FIELD_) (sizeof(((TYPE_ *)0)->FIELD_))
133 #endif
134
135 #ifndef RTL_SIZEOF_THROUGH_FIELD
136 #define RTL_SIZEOF_THROUGH_FIELD(TYPE_, FIELD_) \
137 (FIELD_OFFSET(TYPE_, FIELD_) + RTL_FIELD_SIZE(TYPE_, FIELD_))
138 #endif
139
140 #ifndef RTL_CONTAINS_FIELD
141 #define RTL_CONTAINS_FIELD(P_, SIZE_, FIELD_) \
142 ((ULONG_PTR)(P_) + (ULONG_PTR)(SIZE_) > (ULONG_PTR)&((P_)->FIELD_) + sizeof((P_)->FIELD_))
143 #endif
144
145 #define ELFFMT_FIELDS_EQUAL(TYPE1_, TYPE2_, FIELD_) \
146 ( \
147 (FIELD_OFFSET(TYPE1_, FIELD_) == FIELD_OFFSET(TYPE2_, FIELD_)) && \
148 (RTL_FIELD_SIZE(TYPE1_, FIELD_) == RTL_FIELD_SIZE(TYPE2_, FIELD_)) \
149 )
150
151 #define ELFFMT_MAKE_ULONG64(BYTE1_, BYTE2_, BYTE3_, BYTE4_, BYTE5_, BYTE6_, BYTE7_, BYTE8_) \
152 ( \
153 (((ULONG64)ELFFMT_MAKE_ULONG(BYTE1_, BYTE2_, BYTE3_, BYTE4_)) << 0) | \
154 (((ULONG64)ELFFMT_MAKE_ULONG(BYTE5_, BYTE6_, BYTE7_, BYTE8_)) << 32) \
155 )
156
157 #define ELFFMT_MAKE_ULONG(BYTE1_, BYTE2_, BYTE3_, BYTE4_) \
158 ( \
159 (((ULONG)ELFFMT_MAKE_USHORT(BYTE1_, BYTE2_)) << 0) | \
160 (((ULONG)ELFFMT_MAKE_USHORT(BYTE3_, BYTE4_)) << 16) \
161 )
162
163 #define ELFFMT_MAKE_USHORT(BYTE1_, BYTE2_) \
164 ( \
165 (((USHORT)(BYTE1_)) << 0) | \
166 (((USHORT)(BYTE2_)) << 8) \
167 )
168
169 static __inline ULONG64 ElfFmtpReadULong64
170 (
171 IN ULONG64 Input,
172 IN ULONG DataType
173 )
174 {
175 PBYTE p;
176
177 if(DataType == ELF_TARG_DATA)
178 return Input;
179
180 p = (PBYTE)&Input;
181
182 switch(DataType)
183 {
184 case ELFDATA2LSB: return ELFFMT_MAKE_ULONG64(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
185 case ELFDATA2MSB: return ELFFMT_MAKE_ULONG64(p[7], p[6], p[5], p[4], p[3], p[2], p[1], p[0]);
186 }
187
188 ASSERT(FALSE);
189 return (ULONG64)-1;
190 }
191
192 static __inline ULONG ElfFmtpReadULong
193 (
194 IN ULONG Input,
195 IN ULONG DataType
196 )
197 {
198 PBYTE p;
199
200 if(DataType == ELF_TARG_DATA)
201 return Input;
202
203 p = (PBYTE)&Input;
204
205 switch(DataType)
206 {
207 case ELFDATA2LSB: return ELFFMT_MAKE_ULONG(p[0], p[1], p[2], p[3]);
208 case ELFDATA2MSB: return ELFFMT_MAKE_ULONG(p[3], p[2], p[1], p[0]);
209 }
210
211 ASSERT(FALSE);
212 return (ULONG)-1;
213 }
214
215 static __inline USHORT ElfFmtpReadUShort
216 (
217 IN USHORT Input,
218 IN ULONG DataType
219 )
220 {
221 PBYTE p;
222
223 if(DataType == ELF_TARG_DATA)
224 return Input;
225
226 p = (PBYTE)&Input;
227
228 switch(DataType)
229 {
230 case ELFDATA2LSB: return ELFFMT_MAKE_USHORT(p[0], p[1]);
231 case ELFDATA2MSB: return ELFFMT_MAKE_USHORT(p[1], p[0]);
232 }
233
234 ASSERT(FALSE);
235 return (USHORT)-1;
236 }
237
238 static __inline ULONG64 ElfFmtpSafeReadULong64
239 (
240 IN CONST ULONG64 * Input,
241 IN ULONG DataType
242 )
243 {
244 PBYTE p;
245 ULONG64 nSafeInput;
246
247 RtlRetrieveUlonglong(&nSafeInput, Input);
248
249 p = (PBYTE)&nSafeInput;
250
251 switch(DataType)
252 {
253 case ELFDATA2LSB: return ELFFMT_MAKE_ULONG64(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
254 case ELFDATA2MSB: return ELFFMT_MAKE_ULONG64(p[7], p[6], p[5], p[4], p[3], p[2], p[1], p[0]);
255 }
256
257 ASSERT(FALSE);
258 return (ULONG64)-1;
259 }
260
261 static __inline ULONG ElfFmtpSafeReadULong
262 (
263 IN CONST ULONG32 * Input,
264 IN ULONG DataType
265 )
266 {
267 PBYTE p;
268 ULONG nSafeInput;
269 union
270 {
271 CONST ULONG32 *ConstInput;
272 ULONG32 *Input;
273 }pInput = {Input};
274
275 RtlRetrieveUlong(&nSafeInput, pInput.Input);
276
277 if(DataType == ELF_TARG_DATA)
278 return nSafeInput;
279
280 p = (PBYTE)&nSafeInput;
281
282 switch(DataType)
283 {
284 case ELFDATA2LSB: return ELFFMT_MAKE_ULONG(p[0], p[1], p[2], p[3]);
285 case ELFDATA2MSB: return ELFFMT_MAKE_ULONG(p[3], p[2], p[1], p[0]);
286 }
287
288 ASSERT(FALSE);
289 return (ULONG)-1;
290 }
291
292 static __inline BOOLEAN ElfFmtpIsPowerOf2(IN Elf_Addr Number)
293 {
294 if(Number == 0)
295 return FALSE;
296
297 while((Number % 2) == 0)
298 Number /= 2;
299
300 return Number == 1;
301 }
302
303 static __inline Elf_Addr ElfFmtpModPow2
304 (
305 IN Elf_Addr Address,
306 IN Elf_Addr Alignment
307 )
308 {
309 ASSERT(sizeof(Elf_Addr) == sizeof(Elf_Size));
310 ASSERT(sizeof(Elf_Addr) == sizeof(Elf_Off));
311 ASSERT(ElfFmtpIsPowerOf2(Alignment));
312 return Address & (Alignment - 1);
313 }
314
315 static __inline Elf_Addr ElfFmtpAlignDown
316 (
317 IN Elf_Addr Address,
318 IN Elf_Addr Alignment
319 )
320 {
321 ASSERT(sizeof(Elf_Addr) == sizeof(Elf_Size));
322 ASSERT(sizeof(Elf_Addr) == sizeof(Elf_Off));
323 ASSERT(ElfFmtpIsPowerOf2(Alignment));
324 return Address & ~(Alignment - 1);
325 }
326
327 static __inline BOOLEAN ElfFmtpAlignUp
328 (
329 OUT Elf_Addr * AlignedAddress,
330 IN Elf_Addr Address,
331 IN Elf_Addr Alignment
332 )
333 {
334 Elf_Addr nExcess = ElfFmtpModPow2(Address, Alignment);
335
336 if(nExcess == 0)
337 {
338 *AlignedAddress = Address;
339 return nExcess == 0;
340 }
341 else
342 return ElfFmtpAddSize(AlignedAddress, Address, Alignment - nExcess);
343 }
344
345 /*
346 References:
347 [1] Tool Interface Standards (TIS) Committee, "Executable and Linking Format
348 (ELF) Specification", Version 1.2
349 */
350 NTSTATUS NTAPI
351 #if __ELF_WORD_SIZE == 32
352 Elf32FmtCreateSection
353 #elif __ELF_WORD_SIZE == 64
354 Elf64FmtCreateSection
355 #endif
356 (
357 IN CONST VOID * FileHeader,
358 IN SIZE_T FileHeaderSize,
359 IN PVOID File,
360 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
361 OUT PULONG Flags,
362 IN PEXEFMT_CB_READ_FILE ReadFileCb,
363 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
364 )
365 {
366 NTSTATUS nStatus;
367 const Elf_Ehdr * pehHeader;
368 const Elf_Phdr * pphPHdrs;
369 BOOLEAN fPageAligned;
370 ULONG nData;
371 ULONG nPHdrCount;
372 ULONG cbPHdrSize;
373 Elf_Off cbPHdrOffset;
374 PVOID pBuffer;
375 PMM_SECTION_SEGMENT pssSegments;
376 Elf_Addr nImageBase = 0;
377 Elf_Addr nEntryPoint;
378 ULONG32 nPrevVirtualEndOfSegment = 0;
379 ULONG i;
380 ULONG j;
381
382 (void)Intsafe_AddULong64;
383 (void)Intsafe_MulULong32;
384 (void)ElfFmtpReadULong64;
385 (void)ElfFmtpSafeReadULong64;
386 (void)ElfFmtpReadULong;
387
388 #define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
389
390 pBuffer = NULL;
391
392 nStatus = STATUS_INVALID_IMAGE_FORMAT;
393
394 /* Ensure the file contains the full header */
395 /*
396 EXEFMT_LOAD_HEADER_SIZE is 8KB: enough to contain an ELF header (at least in
397 all the classes defined as of December 2004). If FileHeaderSize is less than
398 sizeof(Elf_Ehdr), it means the file itself is small enough not to contain a
399 full ELF header
400 */
401 ASSERT(sizeof(Elf_Ehdr) <= EXEFMT_LOAD_HEADER_SIZE);
402
403 if(FileHeaderSize < sizeof(Elf_Ehdr))
404 DIE(("The file is truncated, doesn't contain the full header\n"));
405
406 pehHeader = FileHeader;
407 ASSERT(((ULONG_PTR)pehHeader % TYPE_ALIGNMENT(Elf_Ehdr)) == 0);
408
409 nData = pehHeader->e_ident[EI_DATA];
410
411 /* Validate the header */
412 if(ElfFmtpReadUShort(pehHeader->e_ehsize, nData) < sizeof(Elf_Ehdr))
413 DIE(("Inconsistent value for e_ehsize\n"));
414
415 /* Calculate size and offset of the program headers */
416 cbPHdrSize = ElfFmtpReadUShort(pehHeader->e_phentsize, nData);
417
418 if(cbPHdrSize != sizeof(Elf_Phdr))
419 DIE(("Inconsistent value for e_phentsize\n"));
420
421 /* MAXUSHORT * MAXUSHORT < MAXULONG */
422 nPHdrCount = ElfFmtpReadUShort(pehHeader->e_phnum, nData);
423 ASSERT(Intsafe_CanMulULong32(cbPHdrSize, nPHdrCount));
424 cbPHdrSize *= nPHdrCount;
425
426 cbPHdrOffset = ElfFmtpReadOff(pehHeader->e_phoff, nData);
427
428 /* The initial header doesn't contain the program headers */
429 if(cbPHdrOffset > FileHeaderSize || cbPHdrSize > (FileHeaderSize - cbPHdrOffset))
430 {
431 NTSTATUS nReadStatus;
432 LARGE_INTEGER lnOffset;
433 PVOID pData;
434 ULONG cbReadSize;
435
436 /* Will worry about this when ELF128 comes */
437 ASSERT(sizeof(cbPHdrOffset) <= sizeof(lnOffset.QuadPart));
438
439 lnOffset.QuadPart = (LONG64)cbPHdrOffset;
440
441 /*
442 We can't support executable files larger than 8 Exabytes - it's a limitation
443 of the I/O system (only 63-bit offsets are supported). Quote:
444
445 [...] the total amount of printed material in the world is estimated to be
446 around a fifth of an exabyte. [...] [Source: Wikipedia]
447 */
448 if(lnOffset.u.HighPart < 0)
449 DIE(("The program header is too far into the file\n"));
450
451 nReadStatus = ReadFileCb
452 (
453 File,
454 &lnOffset,
455 cbPHdrSize,
456 &pData,
457 &pBuffer,
458 &cbReadSize
459 );
460
461 if(!NT_SUCCESS(nReadStatus))
462 {
463 nStatus = nReadStatus;
464 DIE(("ReadFile failed, status %08X\n", nStatus));
465 }
466
467 ASSERT(pData);
468 ASSERT(pBuffer);
469 ASSERT(Intsafe_CanOffsetPointer(pData, cbReadSize));
470
471 if(cbReadSize < cbPHdrSize)
472 DIE(("The file didn't contain the program headers\n"));
473
474 /* Force the buffer to be aligned */
475 if((ULONG_PTR)pData % TYPE_ALIGNMENT(Elf_Phdr))
476 {
477 ASSERT(((ULONG_PTR)pBuffer % TYPE_ALIGNMENT(Elf_Phdr)) == 0);
478 RtlMoveMemory(pBuffer, pData, cbPHdrSize);
479 pphPHdrs = pBuffer;
480 }
481 else
482 pphPHdrs = pData;
483 }
484 else
485 {
486 ASSERT(Intsafe_CanAddSizeT(cbPHdrOffset, 0));
487 ASSERT(Intsafe_CanOffsetPointer(FileHeader, cbPHdrOffset));
488 pphPHdrs = (PVOID)((ULONG_PTR)FileHeader + (ULONG_PTR)cbPHdrOffset);
489 }
490
491 /* Allocate the segments */
492 pssSegments = AllocateSegmentsCb(nPHdrCount);
493
494 if(pssSegments == NULL)
495 {
496 nStatus = STATUS_INSUFFICIENT_RESOURCES;
497 DIE(("Out of memory\n"));
498 }
499
500 ImageSectionObject->Segments = pssSegments;
501
502 fPageAligned = TRUE;
503
504 /* Fill in the segments */
505 for(i = 0, j = 0; i < nPHdrCount; ++ i)
506 {
507 switch(ElfFmtpSafeReadULong(&pphPHdrs[i].p_type, nData))
508 {
509 case PT_LOAD:
510 {
511 static const ULONG ProgramHeaderFlagsToProtect[8] =
512 {
513 PAGE_NOACCESS, /* 0 */
514 PAGE_EXECUTE_READ, /* PF_X */
515 PAGE_READWRITE, /* PF_W */
516 PAGE_EXECUTE_READWRITE, /* PF_X | PF_W */
517 PAGE_READONLY, /* PF_R */
518 PAGE_EXECUTE_READ, /* PF_X | PF_R */
519 PAGE_READWRITE, /* PF_W | PF_R */
520 PAGE_EXECUTE_READWRITE /* PF_X | PF_W | PF_R */
521 };
522
523 Elf_Size nAlignment;
524 Elf_Off nFileOffset;
525 Elf_Addr nVirtualAddr;
526 Elf_Size nAdj;
527 Elf_Size nVirtualSize = 0;
528 Elf_Size nFileSize = 0;
529
530 ASSERT(j <= nPHdrCount);
531
532 /* Retrieve and validate the segment alignment */
533 nAlignment = ElfFmtpSafeReadSize(&pphPHdrs[i].p_align, nData);
534
535 if(nAlignment == 0)
536 nAlignment = 1;
537 else if(!ElfFmtpIsPowerOf2(nAlignment))
538 DIE(("Alignment of loadable segment isn't a power of 2\n"));
539
540 if(nAlignment < PAGE_SIZE)
541 fPageAligned = FALSE;
542
543 /* Retrieve the addresses and calculate the adjustment */
544 nFileOffset = ElfFmtpSafeReadOff(&pphPHdrs[i].p_offset, nData);
545 nVirtualAddr = ElfFmtpSafeReadAddr(&pphPHdrs[i].p_vaddr, nData);
546
547 nAdj = ElfFmtpModPow2(nFileOffset, nAlignment);
548
549 if(nAdj != ElfFmtpModPow2(nVirtualAddr, nAlignment))
550 DIE(("File and memory address of loadable segment not congruent modulo alignment\n"));
551
552 /* Retrieve, adjust and align the file size and memory size */
553 if(!ElfFmtpAddSize(&nFileSize, ElfFmtpSafeReadSize(&pphPHdrs[i].p_filesz, nData), nAdj))
554 DIE(("Can't adjust the file size of loadable segment\n"));
555
556 if(!ElfFmtpAddSize(&nVirtualSize, ElfFmtpSafeReadSize(&pphPHdrs[i].p_memsz, nData), nAdj))
557 DIE(("Can't adjust the memory size of lodable segment\n"));
558
559 if(!ElfFmtpAlignUp(&nVirtualSize, nVirtualSize, nAlignment))
560 DIE(("Can't align the memory size of lodable segment\n"));
561
562 if(nFileSize > nVirtualSize)
563 nFileSize = nVirtualSize;
564
565 if(nVirtualSize > MAXULONG)
566 DIE(("Virtual image larger than 4GB\n"));
567
568 ASSERT(nFileSize <= MAXULONG);
569
570 pssSegments[j].Length = (ULONG)(nVirtualSize & 0xFFFFFFFF);
571 pssSegments[j].RawLength = (ULONG)(nFileSize & 0xFFFFFFFF);
572
573 /* File offset */
574 nFileOffset = ElfFmtpAlignDown(nFileOffset, nAlignment);
575
576 #if __ELF_WORD_SIZE >= 64
577 ASSERT(sizeof(nFileOffset) == sizeof(LONG64));
578
579 if(((LONG64)nFileOffset) < 0)
580 DIE(("File offset of loadable segment is too large\n"));
581 #endif
582
583 pssSegments[j].FileOffset = (LONG64)nFileOffset;
584
585 /* Virtual address */
586 nVirtualAddr = ElfFmtpAlignDown(nVirtualAddr, nAlignment);
587
588 if(j == 0)
589 {
590 /* First segment: its address is the base address of the image */
591 nImageBase = nVirtualAddr;
592 pssSegments[j].VirtualAddress = 0;
593
594 /* Several places make this assumption */
595 if(pssSegments[j].FileOffset != 0)
596 DIE(("First loadable segment doesn't contain the ELF header\n"));
597 }
598 else
599 {
600 Elf_Size nVirtualOffset;
601
602 /* Other segment: store the offset from the base address */
603 if(nVirtualAddr <= nImageBase)
604 DIE(("Loadable segments are not sorted\n"));
605
606 nVirtualOffset = nVirtualAddr - nImageBase;
607
608 if(nVirtualOffset > MAXULONG)
609 DIE(("Virtual image larger than 4GB\n"));
610
611 pssSegments[j].VirtualAddress = (ULONG)(nVirtualOffset & 0xFFFFFFFF);
612
613 if(pssSegments[j].VirtualAddress != nPrevVirtualEndOfSegment)
614 DIE(("Loadable segments are not sorted and contiguous\n"));
615 }
616
617 /* Memory protection */
618 pssSegments[j].Protection = ProgramHeaderFlagsToProtect
619 [
620 ElfFmtpSafeReadULong(&pphPHdrs[i].p_flags, nData) & (PF_R | PF_W | PF_X)
621 ];
622
623 /* Characteristics */
624 /*
625 TODO: need to add support for the shared, non-pageable, non-cacheable and
626 discardable attributes. This involves extensions to the ELF format, so it's
627 nothing to be taken lightly
628 */
629 if(pssSegments[j].Protection & PAGE_IS_EXECUTABLE)
630 {
631 ImageSectionObject->Executable = TRUE;
632 pssSegments[j].Characteristics = IMAGE_SCN_CNT_CODE;
633 }
634 else if(pssSegments[j].RawLength == 0)
635 pssSegments[j].Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
636 else
637 pssSegments[j].Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA;
638
639 /*
640 FIXME: see the TODO above. This is the safest way to load ELF drivers, for
641 now, if a bit wasteful of memory
642 */
643 pssSegments[j].Characteristics |= IMAGE_SCN_MEM_NOT_PAGED;
644
645 /* Copy-on-write */
646 pssSegments[j].WriteCopy = TRUE;
647
648 if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment, pssSegments[j].VirtualAddress, pssSegments[j].Length))
649 DIE(("Virtual image larger than 4GB\n"));
650
651 ++ j;
652 break;
653 }
654 }
655 }
656
657 if(j == 0)
658 DIE(("No loadable segments\n"));
659
660 ImageSectionObject->NrSegments = j;
661
662 *Flags =
663 EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED |
664 EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP;
665
666 if(fPageAligned)
667 *Flags |= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED;
668
669 nEntryPoint = ElfFmtpReadAddr(pehHeader->e_entry, nData);
670
671 if(nEntryPoint < nImageBase || nEntryPoint - nImageBase > nPrevVirtualEndOfSegment)
672 DIE(("Entry point not within the virtual image\n"));
673
674 ASSERT(nEntryPoint >= nImageBase);
675 ASSERT((nEntryPoint - nImageBase) <= MAXULONG);
676 ImageSectionObject->EntryPoint = nEntryPoint - nImageBase;
677
678 /* TODO: support Wine executables and read these values from nt_headers */
679 ImageSectionObject->ImageCharacteristics |=
680 IMAGE_FILE_EXECUTABLE_IMAGE |
681 IMAGE_FILE_LINE_NUMS_STRIPPED |
682 IMAGE_FILE_LOCAL_SYMS_STRIPPED |
683 (nImageBase > MAXULONG ? IMAGE_FILE_LARGE_ADDRESS_AWARE : 0) |
684 IMAGE_FILE_DEBUG_STRIPPED;
685
686 if(nData == ELFDATA2LSB)
687 ImageSectionObject->ImageCharacteristics |= IMAGE_FILE_BYTES_REVERSED_LO;
688 else if(nData == ELFDATA2MSB)
689 ImageSectionObject->ImageCharacteristics |= IMAGE_FILE_BYTES_REVERSED_HI;
690
691 /* Base address outside the possible address space */
692 if(nImageBase > MAXULONG_PTR)
693 ImageSectionObject->ImageBase = EXEFMT_LOAD_BASE_NONE;
694 /* Position-independent image, base address doesn't matter */
695 else if(nImageBase == 0)
696 ImageSectionObject->ImageBase = EXEFMT_LOAD_BASE_ANY;
697 /* Use the specified base address */
698 else
699 ImageSectionObject->ImageBase = (ULONG_PTR)nImageBase;
700
701 /* safest bet */
702 ImageSectionObject->Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
703 ImageSectionObject->MinorSubsystemVersion = 0;
704 ImageSectionObject->MajorSubsystemVersion = 4;
705
706 /* Success, at last */
707 nStatus = STATUS_SUCCESS;
708
709 l_Return:
710 if(pBuffer)
711 ExFreePool(pBuffer);
712
713 return nStatus;
714 }
715
716 /* EOF */