So if I call from Nim to C (passing a gc'd Nim-owned pointer), then that C routine calls back into Nim (via a function pointer, or some other way through the FFI), the nested Nim routine may trigger gc and wipe out the pointer my C code is working with?
The situation that you describe could happen, but it is quite rare in practice. Usually, I call c functions that do their work and be done, such as BLAS.
For such cases, you can either manually allocate the pointers you pass to c, or temporarily disable the gc. Each thread has its own heap, so gc for one thread does not break anything in other threads
I don't think so. I think by virtue of having a GC language you pretty much have to manually anchor pointers before calling code which knows nothing of the GC.
But if anyone knows of counter examples, I would be interested in them as well.