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