I'm trying to understand how JIT compiler works. I already understood the basic idea of dynamic code generation at runtime, but I'm not clear about how the generated code links with the program? Through dynamic-link library? It would be nice if somebody could share a "hello world" example of JIT compiler for study.
The simple answer is that the JITter keeps a symbol table around recording the entry points of other functions (compiled or not) complete with signatures, and it keeps abstract object definitions around containing the member variables and assigned offsets into the actual memory realization of the object.
Then when JIT-compiling a function call, it can look up the function (in the classic way a Java pure compiler might), and generate a call. (If it was my JIT system, I'd build a dummy receiving stub in machine code for every uncompiled method, that called the the JITter when it got control. Then every compiled function always calls machine code for the callee. This is in effect an entry in a "DLL" library; you use a stub to hide the real thing.)
On encountering a new class definition, it creates a symbol table entry for that class, finds the member variables, and assigns offsets. (This is slightly complicated by the fact that one class may inherit from another; in a single-inheritance system like Jav, all one really has to do is record assigned offsets for the new member variables taking into account already assigned offets from parent classes).
When JIT-compiling a member variable reference, it looks up the object type, finds the member information, grabs the offset and uses it.
You may find variations of this scheme but in general it has to be something like this. This is all pretty much what a pure compiler would have do anyway; you are just delaying the work until a an object or method is encountered at runtime.