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