In the book Linkers and Loaders, it's mentioned that one of the reasons for executables to have a separate code section is that the code section can be kept in read only pages, which results in a performance increase. Is this still true for a modern OS? Seeing as Just in Time compilers are generating code on the fly, I assume they need writable pages. Does this mean that JIT generated code will always suffer a performance hit in comparison? If so, how significant a hit is it?
Yes, it should suffer some sort of hit because the code in memory is not backed directly by the executable, so it would have to be paged out instead of just dropped. Having said that, various forms of linking can also dirty up regular code pages so that they no longer match the disk image, with the same consequences, so I'm not sure that this is a big deal.
The performance increase is not because of whether the pages are read only or not. The advantage is that read only pages can be shared between processes, so you use less memory which means less swapping (both to L1/L2/L3 caches as well as to disk in extreme cases).
JIT tries to mitigate this by not needlessly JITting, but only JITting the hot functions. This will result in only a modest increase in memory since the number of hot functions are relatively small.
A JIT compiler could also be smart and cache the result of the JITting so it could (theoretically) be shared. But I don't know whether this is done in practice.
Effects of memory management aside (which are explained in other answers), CPU doesn't need to continuously check if the current stream of instructions are modified and the intermediate results in the pipeline should be thrown away and new code needs to be read. In the case of jit compilation, this scenario may occur often depending on the design of the compiler, depth of CPU pipeline, size of code cache on CPU and number of other CPUs which may modify that code. It isn't normally allowed to occur in well designed modern systems where code is generated to a writeable page and marked as executable and readonly afterwards. This is not unique to jit of course. It can happen in all kinds of self modifying code.