C++ – What does the /TSAWARE linker flag do to the PE executable

linkerportable-executablevisual c++visual-c++-6windows

After adding the /TSAWARE linker flag to one of my projects (Visual Studio 6), I was surprised to find a new section in the PE file (.idata). If I don't set the flag, the imports are merged into .rdata.

To illustrate the "problem" we start out with a simple console program:

#include <stdio.h>
int main() 
{
    printf("hello world\n");
    return 0;
}

and compile with: cl /Og /O1 /GF /WX /c main.c

Then link with

  • link /MACHINE:IX86 /SUBSYSTEM:CONSOLE /RELEASE /OUT:a.exe main.obj
  • link /MACHINE:IX86 /SUBSYSTEM:CONSOLE /RELEASE /OUT:b.exe /TSAWARE main.obj

Let's compare the dumpbin output:

Dump of file a.exe

File Type: EXECUTABLE IMAGE

  Summary

        4000 .data
        1000 .rdata
        5000 .text

Dump of file b.exe

File Type: EXECUTABLE IMAGE

  Summary

        4000 .data
        1000 .idata
        1000 .rdata
        5000 .text

So for some reason, the linker decides that the imports cannot be merged.

But if we run editbin /TSAWARE a.exe only the DLL characteristics field in the PE optional header is changed.

Can anyone explain this to me? Is this a bug in the linker or can the executable changed by editbin end up not working on certain systems?

Best Answer

Only a guess: on a terminal server system, you want an image to have a few pages written to as possible. If a memory page that corresponds to the image is not modified, a single page of physical RAM can be mapped into eash session that is using that image. If a page from an image is modified, the system has to perform a copy-on-write operation for each instance of the page among all the sessions and use a different block of physical memory to represent the page in each session.

Since the imports for an image often need to be fixed up if the DLL that is being imported had to be relocated, the pages that hold the imports often get modified and therefore can't participate in sharing between the sessions. If the linker merges the imports with other data that is usually not modified, it might increase the number of copy-on-write pages unnecessarily.

This may be a sort of optimization that helps reduce the number of copied pages across sessions.

Like I said though - this is purely a guess.