Myth: The /3GB switch expands the user-mode address space of all programs


Only programs marked as /LARGEADDRESSAWARE are affected.

For compatibility reasons, only programs that explicitly indicate that they are prepared to handle a virtual address space larger than 2GB will get the larger virtual address space. Unmarked programs get the normal 2GB virtual address space, and the address space between 2GB and 3GB goes unused.

Why?

Because far too many programs assume that the high bit of user-mode virtual addresses is always clear, often unwittingly. MSDN has a page listing some of the ways programs make this assumption. One such assumption you may be making is taking the midpoint between two pointers by using the formula (a+b)/2. As I noted in a previous exercise, this is subject to integer overflow and consequently can result in an erroneous pointer computation. Consequently, you can't just take an existing program that you didn't write, mark it /LARGEADDRESSAWARE, and declare your job done. You have to check with the authors of that program that they verified that their code does not make any 2GB assumptions. (And the fact that the authors didn't mark their program as 3GB-compatible strongly suggests that no such verification has occurred. If it had, they would have marked the program /LARGEADDRESSAWARE!)

Marking your program /LARGEADDRESSAWARE indicates to the operating system, "Go ahead and give this program access to that extra gigabyte of user-mode address space," and as a result, addresses in the third gigabyte become possible return values from memory allocation functions. If you set the "Top down" flag in the memory manager allocation preferences mask (search for "top down"), you can instruct the memory manager to allocate high-address memory first, thereby forcing your program to deal with those addresses sooner than it normally would. This is very handy when testing your program in a /3GB configuration since it forces the troublesome memory addresses to be used sooner than normal.

Exercise: Find the bug in the following function. Hint: What's today's topic?

#define BUFFER_SIZE 32768
BOOL  IsPointerInsideBuffer(const BYTE *p, const BYTE *buffer)
{
  return p >= buffer && p - buffer < BUFFER_SIZE;
}
Comments (46)
  1. Anonymous says:

    enough with the /3GB already!

  2. Anonymous says:

    I am shooting in the dark here. But I think the #define is wrong and should be:

    #define BUFFER_SIZE ((size_t)32768)

    Anyway, if the compiler uses a signed int for the less-than, then it fails when the difference between p and buffer is greater than max int.

  3. Anonymous says:

    If I was being picky I’d say this was a compiler bug.

    Suppose you allocate a 2.5GB array of chars and you subtract a pointer to the start from a pointer to the end. The correct answer is +2.5GB and the compiler should define ptrdiff_t (the type of pointer differences) large enough to hold this. In fact, the compiler defines ptrdiff_t as an int, so it gives you the wrong answer.

  4. Anonymous says:

    Well, this is undefined behavior in the first place using an arbitrary p according to the C standard. But anyway, the cannonical way to do this test is:

    p >= buffer && p < buffer + BUFFER_SIZE.

    Also, (a+b)/2 doesn’t work if a and b are both pointers.

  5. Anonymous says:

    Thanks for pointing this out. This one got me. You might point out there is a util called imagecfg that you can use to set the flag on existing exes. Now whether or not it works properly is a differnt question altogether.

  6. Anonymous says:

    I’m going to elaborate what I said just incase nobody has read that part of the C and C++ standards. Doing range testing or subtraction on pointers is only defined if the 2 pointers belong to the same "allocation block", either taking the sub-addresses of some type allocated on the stack or some chunk of memory returned by an allocation function.

    So this function will either return true if p is in this range or result in undefined behavior (which may include, but not limited to: evaluating to true, evaluating to false, evaluating to a bool that is neither true nor false [yes, the C++ standard talks about that so be careful when reinterpret_cast-ing to bools], a crash, or initiating a sequence for hot lava to flow out of the programmer’s ass). So this function is completely useless in the first place.

    But being practical instead of anal, Qwerty nailed it and it could either be a compiler bug or an implemtation bug if an allocation function allocates more than numeric_limits<ptrdiff_t>::max().

  7. Anonymous says:

    asdf is correct, pointer subtraction is technically legal only if the pointers both reside within the same allocation block. Consequently, there is no compiler bug here as long as you can’t allocate blocks larger than the maximum positive value of ptrdiff_t. Which you can’t.

    In practice, nearly all compilers allow subtraction of pointers from different allocation blocks, but this shifts the burden to the programmer to understand the consequences of this new power.

    The signed integer underflow is the bug. If the two pointers are more than 2GB apart, then the result of the subtraction is a negative number. This type of bug is rather common in programs that are not 3GB-certified.

  8. Anonymous says:

    Thanks for doing these posts and exercises Raymond! I can almost feel myself become a better programmer by watching and learning what’s posted here. Oh and thanks to the other people who post the answers :)

  9. Anonymous says:

    Agreed, asdf, IsPointerInsideBuffer is of questionable value. I can’t remember why anyone would want it, but do remember talking about this with a coworker within 1 month of leaving college.

    I don’t see this as either a compiler or specification bug. It just shows that boundary conditions are hard. Allocating a single buffer greater than 2 gigs should be allowed (even though it definately will fail on a 32 bit machine). Also negative pointer differences should be allowed (even though it is more stable to always keep it positive).

    The sad thing is that I bet these same things will be disscussed again in 50 years when they start hitting the limits of a signed 64 bit integer.

  10. Anonymous says:

    Shouldn’t BUFFER_SIZE above be a const size_t instead of a macro, just to be type-safe?

    And then, yes, there seems no legal way to determine if two pointers are from the same array.

  11. Anonymous says:

    Sorry, my mistake. I’d checked malloc.h (in VC6) which says:

    #define _HEAP_MAXREQ 0xFFFFFFE0

    but I didn’t realise (until I tried it) that HeapAlloc has a limit (of 0x7FFDEFFF on XP).

  12. Anonymous says:

    Legal, yes. Practical, no. Compare for equality with every element in the array.

  13. Anonymous says:

    Really? std::less is defined like this:

    template <class _Tp>

    struct less : public binary_function<_Tp, _Tp, bool>

    {

    bool operator()(const _Tp& __x, const _Tp& __y) const { return __x < __y; }

    };

    Notice that it just uses the boring < operator so you’re back to where you started.

  14. Anonymous says:

    On most implementations, that’s how it is defined but there are some environments where that isn’t the definition.

    20.3.3/8 For templates greater, less, greater_equal, and less_equal, the specializations for any pointer type yield a total order, even if the built-in operators <, >, <=, >= do not.

  15. Anonymous says:

    I think all this pedantry is missing the point somewhat.

    The point is that code like Raymond’s example, which looks semi-reasonable at first glance, almost certainly exists out in the wild, and is buggy when pointers can be beyond 2GB. In particular, notice that it’s possible to have code which fails even when you didn’t explicitly do anything egregiously hacky like storing data in the top bit of a pointer.

  16. Anonymous says:

    What’s going on here is pretty subtle for me. My explanation is that the two comparisons happen in different domains, and it’s the mixing of the domains that makes it fail.

    The first comparison is between pointers; this is in the unsigned "pointer-compare" domain, and a very large P and small Buffer give a result with the high bit on and it’s interpreted as unsigned, so it’s a big number.

    The second comparison is done in the integer domain (technically, the ptrdiff_t domain) which is signed. The p-buffer becomes a very negative number, not a very large positive number, and the comparison returns the "wrong" result.

    This is why the earlier comment (by asdf) that the canonical way to do this is important. By making the second comparison p<buffer+BUFFER_SIZE it stays in the ptrdiff_t domain. By staying in the same domain the results are compatible.

    The code could also be rewritten so the first comparison is in the ptrdiff_t domain: p-buffer > 0. This keeps both compares in the same domain, and so they stay compatible.

    This is also why the STL solution works: it’s not that STL is being so very magical, but that the problem is being rewritten so that the compares are both done in the same domain. The exact nature of the lt is then unimportant: it doesn’t matter whether it’s signed or unsigned just so that it’s consitent.

    I had to vet an old program (RS/1) once for Win32s. That version of Windows had the unique issue that all mallocs() resulted in memory with the high bit on (unlike the dozens of other systems RS/1 had been ported to). I had to check a bunch of pointer arithmetic to make sure that all the mods and divs and everything was nice and compatible.

  17. Anonymous says:

    In C++, the template functor std::less provides an ordering between pointers even if they don’t point into the same array. So I think this should work:

    BOOL IsPointerInsideBuffer(const BYTE *p, const BYTE *buffer)

    {

    std::less<const BYTE *> lt;

    return !lt(p, buffer) && lt(p, buffer + BUFFER_SIZE);

    }

  18. Anonymous says:

    What about /LARGEADDRESSAWARE applications loading non-aware DLLs?

  19. Anonymous says:

    "2GB should be enough for anyone" got this topic right, I think.. nowadays, who cares about the intricacies of the /3GB switch, when you can get yourself a 64-bit CPU and OS. (well, almost, but that’s good enough for stuff I’d be writing today for release in the near future)

    Although, I appreciate this blog immensely, I’d be much more interested in issues with getting my code going on 64-bit windows, or running other people’s code on 64-bit windows than I would with some memory ‘hack’ that is soon to go the way of the large memory model.

  20. Anonymous says:

    "2GB should be enough for anyone" got this topic right, I think.. nowadays, who cares about the intricacies of the /3GB switch, when you can get yourself a 64-bit CPU and OS. (well, almost, but that’s good enough for stuff I’d be writing today for release in the near future)

    Although, I appreciate this blog immensely, I’d be much more interested in issues with getting my code going on 64-bit windows, or running other people’s code on 64-bit windows than I would with some memory ‘hack’ that is soon to go the way of the large memory model.

  21. Anonymous says:

    The problem is that subtracting two pointers results in a *signed* operand, and if the buffer is really large then the signed operand could be negative and overflow.

    typedef _W64 int ptrdiff_t;

    To fix the problem you need to do ((ULONG_PTR)(p – buffer))

  22. Anonymous says:

    "Consequently, there is no compiler bug here as long as you can’t allocate blocks larger than the maximum positive value of ptrdiff_t. Which you can’t. "

    Why not?

    Do ntdll.dll et al. still sit at just under 0x80000000 even with a 3 GiB app?

    That would be sad if true.

  23. Anonymous says:

    Of course they are at the same base address. Moving them would require them to be rebased, and it would break all the bound imports that other images use to call them. You would be throwing away performance for no good reason.

  24. Anonymous says:

    All programs that come with the OS are 3GB-compatible, so it means that every single OS process would have to rebase all the system DLLs. So much for "infrequently".

    And since memory for rebased DLLs is not shared, this would balloon the memory requirements for a system in /3GB mode. Notepad’s memory requirements would go from less than 1MB to over 27MB.

  25. Anonymous says:

    There are other technical reasons why this isn’t possible without modifying the kernel anyway. Not that it would probably be very difficult for Microsoft to do, but there are number of performance optimizations taken that rely on things like ntdll or user32 being at the same base address in every process (like looking up the address of exported functions called by the kernel using one of the kernel mode to user mode call facilities only once, and using those addresses for every process in the system). I suspect the major reason is the massive waste of memory and processor time that rebasing would incur, though.

    Then again, I don’t see any compelling gains to moving the system dlls from their normal spot when you use /3GB. What’s wrong with keeping them where they are, anyway? You aren’t likely to get 1+GB of contiguous address space even if you moved all the system dlls around because of explicit virtual memory allocations and section view mappings happening in various places throughout the address space.

  26. Anonymous says:

    "Only those programs that can benefit from [3GB]."

    Who says that Notepad wouldn’t benefit from 3GB? Maybe somebody has a global hook DLL that takes advantage of 3GB?

    "Why can’t the OS share identically-rebased DLLs?" Because there’s no point in optimizing a scenario that developers are supposed to be avoiding anyway.

  27. Anonymous says:

    "Then again, I don’t see any compelling gains to moving the system dlls from their normal spot when you use /3GB. What’s wrong with keeping them where they are, anyway? You aren’t likely to get 1+GB of contiguous address space even if you moved all the system dlls around because of explicit virtual memory allocations and section view mappings happening in various places throughout the address space. "

    What’s wrong is that they punch a fucking great hole in the address space.

    If you don’t have > 1 GiB of contiguous address space, for example, the CLR won’t load, so it can’t be that infrequent–but in some situations (http://support.microsoft.com/default.aspx?scid=kb;en-us;821157) that’s exactly what happens.

    If, on the other hand, system libraries were loaded at just below 3 GiB for 3 GiB-aware programs then you’d have a clear run all the way from about 2.5 GiB all the way down to about 0.5 GiB, which would make such situations extremely infrequent.

    It’d also be simply more convenient for applications working with large datasets, as it’d reduce their need to use their own custom "paging" mechanism.

  28. Anonymous says:

    It is avoidable if you stay away from the upper end of the address space, which is where system DLLs hang out.

    Even if it’s unavoidable, it occurs rarely.

    What you’re suggesting is taking the rare case and making it the 100% case.

  29. Anonymous says:

    Developers can avoid it in >95% of all cases.

    The vast majority of all dlls loaded in an average app are either system dlls or dlls written to work with the app.

    Sure, once and awhile a hook dll or somesuch might conflict on somebody’s system causing a rebase, but in the overwhelming majority of cases you can avoid having your dlls rebased as long as you change the default base address from 10000000 (probably the most commonly forgotten step of writing a dll – the first thing I do when starting one, actually. Maybe it would be good to have the linker warn about using the default base address in future versions of VC….) and make sure each dll’s base address is unique within the project.

  30. Anonymous says:

    "Of course they are at the same base address. Moving them would require them to be rebased,"

    Which is a one-off cost when starting an application.

    I get the feeling that 3 GiB apps are the kind which start infrequently and run for long periods. As such the cost of rebasing is utterly insignificant.

    On the other hand, more contiguous address space is *always* good.

  31. Anonymous says:

    "All programs that come with the OS are 3GB-compatible, so it means that every single OS process would have to rebase all the system DLLs. So much for "infrequently". "

    So someone would have to be judicious in marking only those programs that can benefit from it as 3 GiB compatible. That’ll take, what, an afternoon’s work?

    "And since memory for rebased DLLs is not shared, this would balloon the memory requirements for a system in /3GB mode. Notepad’s memory requirements would go from less than 1MB to over 27MB."

    Notepad would be a program which doesn’t benefit from 3 GiB, as it doesn’t appear to make a blind bit of difference to the largest file Notepad can open.

    Of course, if the libraries *were* loaded at just under 3 GiB, perhaps it *could* open larger files. Catch-22?

    And why *can’t* the OS share identically-rebased DLLs? I mean, there are obvious difficulties if the same library is rebased to different locations, but if it’s rebased to the same location (which it presumably would be–somewhere just under 3 GiB) there doesn’t seem any obvious reason why it can’t be shared.

  32. Anonymous says:

    "Who says that Notepad wouldn’t benefit from 3GB?"

    The edit control, it seems.

    "Because there’s no point in optimizing a scenario that developers are supposed to be avoiding anyway.

    But developers cannot avoid it, because developers do not know at link-time what libraries a user may have loaded. Rebasing is *inevitable* and *unavoidable*.

  33. Anonymous says:

    8/16/2004 10:08 AM DrPizza

    > If you don’t have > 1 GiB of contiguous

    > address space, for example, the CLR won’t

    > load, so it can’t be that infrequent

    I think you mean "so it can’t be that frequent". If that is what you mean, then I agree and wish to add: One in a million is next Tuesday.

    By the way, I forgot whose blog commented on "one in a million is next Tuesday" but these days surely one in a million is maybe next minute? Around 20 years ago in one embedded system I added a test, requiring some unwanted consumption of CPU time, because: with the number of customers and the relative infrequency of that operation, if we didn’t check for it, one in a million was still going to crash some victim about once every two weeks. CPUs are a bit faster now. Surely now one in a trillion is next Tuesday.

  34. Anonymous says:

    Silly question, but why on earth are you specifying base addresses for DLLs anyway? That’s what load-time is for.

  35. Anonymous says:

    At a frequency of 1Hz, "1 in a million" is every 11.6 days, or roughly 3 times per month.

    Next Tuesday is sounding closer all the time…

  36. Anonymous says:

    "Silly question, but why on earth are you specifying base addresses for DLLs anyway? That’s what load-time is for."

    Because people are vainly trying to avoid their DLLs being rebased, which is bad because Windows doesn’t bother sharing the memory of rebased DLLs.

  37. Anonymous says:

    DrPizza: Well, in every single program on every Windows system I’ve debugged (and that’s a lot, probably in the hundreds), what I’ve said has held true.

    That’s a good enough reason for me. Feel free to do your own research if you don’t agree, of course, but my own experience tells me that you’re making a big deal out of nothing.

  38. Anonymous says:

    "Developers can avoid it in >95% of all cases."

    No, that’s rather the point. They can’t. They can make sure that none of their libraries collide with /each other/. But the problem is, the developer has no control over the end-user’s computer.

    "The vast majority of all dlls loaded in an average app are either system dlls or dlls written to work with the app. "

    Except for the instant messenger idle detection hook at 0x60000000, sundry shell extensions at between 0x10000000 and 0x40000000 (e.g. Office at 0x379b0000), countless OCXs all at 0x10000000 (e.g. Flash), always-rebased libraries like msi.dll or wireless zeroconfiguration (check out those base addresses…). It all adds up to a lot of holes in the address space that aren’t usable.

    This all adds up to make it very easy for a process to have no more than about 500 MB of free contiguous address space.

    "Sure, once and awhile a hook dll or somesuch might conflict on somebody’s system causing a rebase, but in the overwhelming majority of cases you can avoid having your dlls rebased as long as you change the default base address from 10000000 (probably the most commonly forgotten step of writing a dll – the first thing I do when starting one, actually. Maybe it would be good to have the linker warn about using the default base address in future versions of VC….) and make sure each dll’s base address is unique within the project. "

    Rebased DLLs are *inevitable* and occur even as part of the default configuration.

  39. Anonymous says:

    "I’ve got office installed. Here’s an example of an app (Notepad) that has the open file common dialog up:"

    Office 2000? That’s the one that’s currently plonking a library in the middle of my address space.

    "I really don’t see where you are getting this idea that virtually process has lots and lots of rebased dlls. "

    I didn’t say it did. I said that every system has some rebased DLLs. Windows 2000’s msi.dll seems to be consistently rebased, for example.

  40. Anonymous says:

    "That’s a good enough reason for me. Feel free to do your own research if you don’t agree, of course, but my own experience tells me that you’re making a big deal out of nothing. "

    Every (modern, at least) Windows version has rebased DLLs *out of the box*.

    Your experience is *wrong* if it says that rebasing is at all rare.

    The top 500-odd MB are off-limits due to system .dlls. The bottom 250 off-limits due to the application and its .dlls. Then we have things like Explorer’s Shell/namespace extensions which load in a scattergun approach; Office, for example, loading at about 750 MB. "But why would they load into your application?" You ask. Simple, really–they get dragged into any process that uses a common file dialogue.

    And now you’ve got less than 1 GiB contiguous address space available. It’s not like Office is a niche application to have; it’s *quite* widely used….

  41. Anonymous says:

    I’ve got office installed. Here’s an example of an app (Notepad) that has the open file common dialog up:

    0:004> lm t

    start end module name

    009d0000 009df000 Vxdif Timestamp: Tue Nov 19 08:34:44 2002 (3DDA3DF4) Checksum: 00000000

    01000000 01014000 notepad Timestamp: Tue Mar 25 02:10:14 2003 (3E8000D6) Checksum: 000123BB

    10000000 10112000 Apoint Timestamp: Thu Nov 28 01:05:09 2002 (3DE5B215) Checksum: 00000000

    60970000 60979000 mslbui Timestamp: Tue Mar 25 04:46:43 2003 (3E802583) Checksum: 000112FE

    70ad0000 70bb6000 COMCTL32 Timestamp: Tue Mar 25 04:43:33 2003 (3E8024C5) Checksum: 000E7161

    71b70000 71ba3000 UxTheme Timestamp: Tue Mar 25 04:43:26 2003 (3E8024BE) Checksum: 000340A1

    71bf0000 71bf8000 WS2HELP Timestamp: Tue Mar 25 04:43:26 2003 (3E8024BE) Checksum: 0000B6AB

    71c00000 71c18000 WS2_32 Timestamp: Tue Mar 25 04:43:26 2003 (3E8024BE) Checksum: 00022613

    71c40000 71c93000 NETAPI32 Timestamp: Tue Mar 25 04:43:26 2003 (3E8024BE) Checksum: 00058483

    73070000 73096000 WINSPOOL Timestamp: Tue Mar 25 04:43:17 2003 (3E8024B5) Checksum: 0002C96E

    744f0000 7453b000 MSCTF Timestamp: Tue Mar 25 04:43:07 2003 (3E8024AB) Checksum: 00053F50

    75970000 75a2a000 USERENV Timestamp: Tue Mar 25 04:42:58 2003 (3E8024A2) Checksum: 000C15AA

    75e60000 75e82000 appHelp Timestamp: Tue Mar 25 04:42:57 2003 (3E8024A1) Checksum: 0002A1FE

    75eb0000 75fb6000 browseui Timestamp: Thu Jul 08 19:25:07 2004 (40EDE5E3) Checksum: 00106684

    762b0000 762f7000 comdlg32 Timestamp: Tue Mar 25 04:42:55 2003 (3E80249F) Checksum: 0004C19F

    76300000 76514000 msi Timestamp: Tue Mar 25 04:42:54 2003 (3E80249E) Checksum: 002140A0

    765a0000 766a0000 SETUPAPI Timestamp: Tue Mar 25 04:42:54 2003 (3E80249E) Checksum: 000FE0F9

    768f0000 76914000 ntshrui Timestamp: Tue Mar 25 04:42:52 2003 (3E80249C) Checksum: 0002A48F

    76920000 76a77000 shdocvw Timestamp: Thu Jul 08 19:25:08 2004 (40EDE5E4) Checksum: 0015E185

    76f90000 7700e000 CLBCatQ Timestamp: Mon Mar 15 22:08:57 2004 (40566FC9) Checksum: 000837A0

    77010000 770d6000 COMRes Timestamp: Tue Mar 25 04:42:49 2003 (3E802499) Checksum: 000C4402

    770e0000 7715d000 OLEAUT32 Timestamp: Tue Mar 25 04:42:48 2003 (3E802498) Checksum: 0007D084

    77160000 77285000 ole32 Timestamp: Mon Mar 15 22:08:56 2004 (40566FC8) Checksum: 00129304

    77290000 772d9000 SHLWAPI Timestamp: Thu Jul 08 19:25:08 2004 (40EDE5E4) Checksum: 000521B7

    77380000 77b5e000 SHELL32 Timestamp: Wed May 12 19:07:37 2004 (40A2BC49) Checksum: 007CC594

    77b90000 77b98000 VERSION Timestamp: Tue Mar 25 04:42:46 2003 (3E802496) Checksum: 0000CD51

    77ba0000 77bf4000 msvcrt Timestamp: Tue Mar 25 04:42:46 2003 (3E802496) Checksum: 0005D4DB

    77c00000 77c44000 GDI32 Timestamp: Tue Mar 25 04:42:46 2003 (3E802496) Checksum: 00042EEA

    77c50000 77cf5000 RPCRT4 Timestamp: Mon Mar 15 22:08:57 2004 (40566FC9) Checksum: 000A240C

    77d00000 77d8f000 USER32 Timestamp: Wed Aug 06 16:43:59 2003 (3F31769F) Checksum: 0008FBF9

    77da0000 77e30000 ADVAPI32 Timestamp: Tue Mar 25 04:42:45 2003 (3E802495) Checksum: 00097775

    77e40000 77f34000 kernel32 Timestamp: Tue Mar 25 04:42:44 2003 (3E802494) Checksum: 000F488C

    77f40000 77ffa000 ntdll Timestamp: Tue Mar 25 04:42:44 2003 (3E802494) Checksum: 000B6DBA

    Of all these dlls, there is exactly *one* that got rebased – Vxdif.dll, a third party hook dll that nobody bothered to move from 10000000.

    We can also take a look at the example you suggested, Word itself:

    0:007> lm t

    start end module name

    01830000 0183f000 Vxdif Timestamp: Tue Nov 19 08:34:44 2002 (3DDA3DF4) Checksum: 00000000

    06470000 06582000 Apoint Timestamp: Thu Nov 28 01:05:09 2002 (3DE5B215) Checksum: 00000000

    10000000 1005b000 SKCHUI Timestamp: Wed Feb 07 04:09:58 2001 (3A8110E6) Checksum: 00064FB0

    30000000 30a4b000 WINWORD Timestamp: Thu Jan 15 19:11:23 2004 (40072C2B) Checksum: 00A2652E

    30b00000 3145e000 mso Timestamp: Thu Jan 29 18:35:38 2004 (401998CA) Checksum: 0096240E

    32520000 32532000 msohev Timestamp: Mon Feb 12 20:42:31 2001 (3A889107) Checksum: 00019384

    34eb0000 34ec9000 ENVELOPE Timestamp: Mon Oct 13 13:27:06 2003 (3F8AEE7A) Checksum: 00022B91

    35190000 351a1000 SENDTO Timestamp: Sat Feb 17 18:07:46 2001 (3A8F0442) Checksum: 00017F65

    35230000 35236000 envelopr Timestamp: Mon Feb 26 20:14:11 2001 (3A9AFF63) Checksum: 0000D65D

    3c640000 3c666000 FNAME Timestamp: Mon Oct 13 13:37:06 2003 (3F8AF0D2) Checksum: 0002A014

    3c740000 3c77d000 MOFL Timestamp: Mon Oct 13 13:38:00 2003 (3F8AF108) Checksum: 000452FB

    3e000000 3e0f1000 srintl Timestamp: Mon Dec 18 19:01:54 2000 (3A3EA572) Checksum: 00000000

    3f000000 3f015000 MSSPELL3 Timestamp: Fri Feb 15 19:26:07 2002 (3C6DA71F) Checksum: 0001FBD2

    3f100000 3f431000 MSGR3EN Timestamp: Fri Nov 03 23:39:13 2000 (3A0392F1) Checksum: 003311A0

    48000000 4807d000 riched20 Timestamp: Mon Sep 15 14:32:10 2003 (3F6613BA) Checksum: 00085FD7

    5bc50000 5bc88000 sptip Timestamp: Tue Mar 25 04:46:57 2003 (3E802591) Checksum: 00039F23

    5cc10000 5ccbe000 sapi Timestamp: Tue Mar 25 04:46:02 2003 (3E80255A) Checksum: 000B7437

    60970000 60979000 mslbui Timestamp: Tue Mar 25 04:46:43 2003 (3E802583) Checksum: 000112FE

    64e30000 64e6d000 icm32 Timestamp: Tue Mar 25 04:45:11 2003 (3E802527) Checksum: 0004571F

    6e210000 6e254000 CNBJUI2 Timestamp: Tue Mar 25 04:45:56 2003 (3E802554) Checksum: 0004AF41

    6e2c0000 6e2dd000 CNBJDRV2 Timestamp: Tue Mar 25 04:45:53 2003 (3E802551) Checksum: 0002A634

    70ad0000 70bb6000 comctl32 Timestamp: Tue Mar 25 04:43:33 2003 (3E8024C5) Checksum: 000E7161

    70bc0000 70c50000 COMCTL32_70bc0000 Timestamp: Tue Mar 25 04:43:33 2003 (3E8024C5) Checksum: 00096B96

    71640000 71805000 AcGenral Timestamp: Tue Mar 25 04:43:30 2003 (3E8024C2) Checksum: 001CA751

    71af0000 71b1a000 ShimEng Timestamp: Tue Mar 25 04:43:27 2003 (3E8024BF) Checksum: 0001C598

    71b70000 71ba3000 UxTheme Timestamp: Tue Mar 25 04:43:26 2003 (3E8024BE) Checksum: 000340A1

    71bf0000 71bf8000 WS2HELP Timestamp: Tue Mar 25 04:43:26 2003 (3E8024BE) Checksum: 0000B6AB

    71c00000 71c18000 WS2_32 Timestamp: Tue Mar 25 04:43:26 2003 (3E8024BE) Checksum: 00022613

    71c20000 71c31000 tsappcmp Timestamp: Tue Mar 25 04:43:26 2003 (3E8024BE) Checksum: 0001A640

    71c40000 71c93000 NETAPI32 Timestamp: Tue Mar 25 04:43:26 2003 (3E8024BE) Checksum: 00058483

    72e50000 72f9a000 msxml3 Timestamp: Tue Mar 25 04:43:17 2003 (3E8024B5) Checksum: 0015153E

    73070000 73096000 winspool Timestamp: Tue Mar 25 04:43:17 2003 (3E8024B5) Checksum: 0002C96E

    73aa0000 73ab4000 mscms Timestamp: Tue Mar 25 04:43:12 2003 (3E8024B0) Checksum: 0001D328

    73b30000 73b36000 dciman32 Timestamp: Tue Mar 25 04:43:12 2003 (3E8024B0) Checksum: 0000E248

    744c0000 744e8000 msimtf Timestamp: Tue Mar 25 04:43:08 2003 (3E8024AC) Checksum: 000290E4

    744f0000 7453b000 MSCTF Timestamp: Tue Mar 25 04:43:07 2003 (3E8024AB) Checksum: 00053F50

    74540000 745d2000 mlang Timestamp: Tue Mar 25 04:43:06 2003 (3E8024AA) Checksum: 00091197

    74a80000 74aaf000 OLEACC Timestamp: Tue Mar 25 04:43:05 2003 (3E8024A9) Checksum: 00036548

    75970000 75a2a000 USERENV Timestamp: Tue Mar 25 04:42:58 2003 (3E8024A2) Checksum: 000C15AA

    75da0000 75e5a000 SXS Timestamp: Tue Mar 25 04:42:57 2003 (3E8024A1) Checksum: 000C0304

    75e60000 75e82000 appHelp Timestamp: Tue Mar 25 04:42:57 2003 (3E8024A1) Checksum: 0002A1FE

    75eb0000 75fb6000 browseui Timestamp: Thu Jul 08 19:25:07 2004 (40EDE5E3) Checksum: 00106684

    75fc0000 76048000 urlmon Timestamp: Thu Jul 08 19:25:08 2004 (40EDE5E4) Checksum: 000881F2

    76260000 76270000 WINSTA Timestamp: Tue Mar 25 04:42:55 2003 (3E80249F) Checksum: 00016513

    76290000 762ad000 imm32 Timestamp: Tue Mar 25 04:42:55 2003 (3E80249F) Checksum: 0002809C

    762b0000 762f7000 comdlg32 Timestamp: Tue Mar 25 04:42:55 2003 (3E80249F) Checksum: 0004C19F

    76300000 76514000 msi Timestamp: Tue Mar 25 04:42:54 2003 (3E80249E) Checksum: 002140A0

    76520000 7653d000 CSCDLL Timestamp: Tue Mar 25 04:42:54 2003 (3E80249E) Checksum: 0001D865

    76540000 76590000 cscui Timestamp: Tue Mar 25 04:42:54 2003 (3E80249E) Checksum: 00051C4C

    765a0000 766a0000 SETUPAPI Timestamp: Tue Mar 25 04:42:54 2003 (3E80249E) Checksum: 000FE0F9

    766d0000 766d9000 SHFOLDER Timestamp: Tue Mar 25 04:42:53 2003 (3E80249D) Checksum: 0000FE87

    767a0000 767d5000 UNIDRVUI Timestamp: Tue Mar 25 04:42:53 2003 (3E80249D) Checksum: 000338C4

    767e0000 76823000 UNIDRV Timestamp: Tue Mar 25 04:42:53 2003 (3E80249D) Checksum: 00048FF4

    768e0000 768e8000 LINKINFO Timestamp: Tue Mar 25 04:42:52 2003 (3E80249C) Checksum: 0000C1C0

    768f0000 76914000 ntshrui Timestamp: Tue Mar 25 04:42:52 2003 (3E80249C) Checksum: 0002A48F

    76920000 76a77000 shdocvw Timestamp: Thu Jul 08 19:25:08 2004 (40EDE5E4) Checksum: 0015E185

    76aa0000 76acc000 WINMM Timestamp: Tue Mar 25 04:42:52 2003 (3E80249C) Checksum: 000384CD

    76f00000 76f08000 wtsapi32 Timestamp: Tue Mar 25 04:42:49 2003 (3E802499) Checksum: 000053F6

    76f50000 76f63000 Secur32 Timestamp: Tue Mar 25 04:42:49 2003 (3E802499) Checksum: 0001508D

    76f90000 7700e000 CLBCatQ Timestamp: Mon Mar 15 22:08:57 2004 (40566FC9) Checksum: 000837A0

    77010000 770d6000 COMRes Timestamp: Tue Mar 25 04:42:49 2003 (3E802499) Checksum: 000C4402

    770e0000 7715d000 OLEAUT32 Timestamp: Tue Mar 25 04:42:48 2003 (3E802498) Checksum: 0007D084

    77160000 77285000 OLE32 Timestamp: Mon Mar 15 22:08:56 2004 (40566FC8) Checksum: 00129304

    77290000 772d9000 SHLWAPI Timestamp: Thu Jul 08 19:25:08 2004 (40EDE5E4) Checksum: 000521B7

    77380000 77b5e000 SHELL32 Timestamp: Wed May 12 19:07:37 2004 (40A2BC49) Checksum: 007CC594

    77b70000 77b84000 MSACM32 Timestamp: Tue Mar 25 04:42:46 2003 (3E802496) Checksum: 00013E94

    77b90000 77b98000 VERSION Timestamp: Tue Mar 25 04:42:46 2003 (3E802496) Checksum: 0000CD51

    77ba0000 77bf4000 msvcrt Timestamp: Tue Mar 25 04:42:46 2003 (3E802496) Checksum: 0005D4DB

    77c00000 77c44000 GDI32 Timestamp: Tue Mar 25 04:42:46 2003 (3E802496) Checksum: 00042EEA

    77c50000 77cf5000 RPCRT4 Timestamp: Mon Mar 15 22:08:57 2004 (40566FC9) Checksum: 000A240C

    77d00000 77d8f000 USER32 Timestamp: Wed Aug 06 16:43:59 2003 (3F31769F) Checksum: 0008FBF9

    77da0000 77e30000 ADVAPI32 Timestamp: Tue Mar 25 04:42:45 2003 (3E802495) Checksum: 00097775

    77e40000 77f34000 kernel32 Timestamp: Tue Mar 25 04:42:44 2003 (3E802494) Checksum: 000F488C

    77f40000 77ffa000 ntdll Timestamp: Tue Mar 25 04:42:44 2003 (3E802494) Checksum: 000B6DBA

    780c0000 78121000 MSVCP60 Timestamp: Wed May 29 16:00:05 2002 (3CF54155) Checksum: 0006243E

    Two dlls got rebased here, Apoint.dll and Vxdif.dll. Coincidentally, both were left at the 10000000 base address.

    I really don’t see where you are getting this idea that virtually process has lots and lots of rebased dlls.

  42. Anonymous says:

    &nbsp; As Evan&nbsp;already mentioned on his blog, Raymond Chen has a great series on /3GB switch on his blog. What is really cool is that Raymond takes on some myths about the /3GB switch and&nbsp; the fact that he…

  43. Anonymous says:

    Not quite &quot;Riffing on Raymond&quot; but he just wrote about this, and it reminded me of a story that was related…

  44. Anonymous says:

    By now you have heard a lot about the fact that under WOW a 32 bit process can get 4GB of VAS.&amp;nbsp;&amp;nbsp;…

Comments are closed.