问题一:"在早期版本的Windows中,Microsoft不允许应用此程序访问2GB以上的地址空间.因此,有些有创意的开发人员决定对此加以利用.他们将指针的最高为作为一个标志位使用,只有他们的应用程序才知道该如何解释该标志位.当应用程序访问内存地址时,会在访问内存地址之前清除指针的最高位.可以想象,当此类应用程序在用户模式分区大于2GB的环境下运行时,"显然会死的很难看""
   请问"他们将指针的最高为作为一个标志位使用,只有他们的应用程序才知道该如何解释该标志位.当应用程序访问内存地址时,会在访问内存地址之前清除指针的最高位" 这样做的目的是什么?
问题二:"在Windows中,所有.exe和动态链接库(dynamic-link library,通常简称DLL)都载入到这一区域(指用户模式分区).每个进程都有可能将这些DLL载入到这一分区内的不同地址(虽然这种可能性很小)."  请问这里又该如何理解?

解决方案 »

  1.   

    dll会共享,这样可以多个进程加载同一份,防止重复加载.
      

  2.   

    1、因为Win32里面,2G以上的空间是不允许用户程序直接访问的,用户只能使用2G以下的地址,即地址空间是
    0x00100000-0x7FFFFFFF
    这样,32位机器上,用户程序的合法指针的最高位0x8000000总是0. 有些程序员就考虑利用这一位,记录一个bool信息。比如,
    void print_msg(void *msg)
    {
      if(((unsigned long)msg)&0x80000000)
      {
        printf("int value: %d\n", *(int)(msg & ~0x80000000));
      }
      else
      {
        printf("string value: %s\n", msg);
      }
    }int main() {
    {
      int a = 10;
      char *b = "hello";
      print_msg( a | 0x8000000);
      print_msg( b );
      return 0;
    }实际上这种做法是非常不好的,尤其是现在从win32向win64迁移的时候,这样的代码是完全不可移植的。2、程序都是载入内存执行的。比如生成一个hello.exe,有64K大小。系统新建一个进程,这个进程可以认为自身拥0x00000000-0xFFFFFFFF的4G地址,把整个hello.exe加载到内存的0x00400000开始的地址,可能才占用0x00400000-0x00410000的地址,还有大量地址可以使用。如果程序中引用了user32.dll,则系统可能把user32.dll加载到0x75000000-0x75400000的地址空间,那么从进程角度看,加入进来的内容,就是进程本身的一部分,并不区分这些内存是从磁盘文件hello.exe里面加载的,还是从磁盘文件user32.dll加载的。实际上,MS编译器编译dll时候建议的地址都是0x10000000,如果生成了两个动态链接库a.dll, b.dll,并且都由hello.exe引用,假设系统已经将a.dll加载到0x10000000开始的地址,那么在加载b.dll的时候,本应该加载到0x10000000开始的地址的,但此地址已经被a.dll占用了,应该使用其它地址(在PE加载里面使用reloc信息来处理)。