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