The GAC can contain non-ngen'd code (it must contain it as well as the native images when using ngen since ngened images do not contain all the needed meta data). Ngen'd code requires the dll be installed in the GAC to function efficiently (technically you can do it without but the resulting name verification triggers full read of your dll anyway which is likely to make your startup time worse).
Pre 3.5 sp1 the ngen compilation was definitely fractionally different from the runtime one see this article for some more details. I would imagine this still holds true for 3.5SP1 since those issues are hard to solve.
Since ngen only really gives you two big wins you should consider whether either/both are significant in your scenario to justify the complexity and cost associated with their use.
- The startup time for those dll's is much reduced
- To be a really big win though all dlls loaded at start up need to be ngened to avoid the overhead of loading the jit itself)
- The native images can share memory space across multiple processes.
- Pretty pointless if you only run one or two processes.
I suggest This article detailing some of the changes in the 2.0 ngen is a good read, it covers things like hard binding which is a big improvement and links in to the excellent general documentation on writing efficient managed code though it has suffered from link rot see msdn Chapter 5 it refers to. (note that that doc is old but many of the themes are still valid)