Umm... all registers are safe to use, provided they're used appropriately. I suppose you mean "when calling C library functions". As I mentioned above, ebp, ebx, esi, and edi are preserved, ecx and edx are trashed and eax is the return value. They're all safe to use, but don't expect eax, ecx, and edx to remain unchanged when you call a C function. That doesn't mean you can't use 'em in between. If you're writing code that returns to C ("main" returns to C - or can), you're expected to follow the same rules - preserve ebp, ebx, esi, and edi. You're not required to trash ecx and edx of course, but you can. You're expected to put the return value (if there is one) in eax. If in doubt, return zero.
The Intel/AMD manuals are probably the best source of info on registers. I can rattle off the "general purpose" registers - eax, ebx, ecx, edx (these ones have byte parts al, ah, bl, bh, etc.), esi, edi (these don't have byte parts - but the 64-bit versions do!), ebp (usually used to point into the stack), and esp (always used by stack instructions call, ret, push, pop - not generally "safe" to use otherwise), they all have 16-bit "word" parts, just leave off the 'e' - but there are segment registers, control registers, debug registers... probably others I know nothing about. You "probably" don't need to use 'em just yet.
I see I forgot to mention the "flags" or "status" (or "eflags" for 32-bit) register. This is not a general purpose register and special instructions apply to it. Individual bits have different meanings and are used/altered in different (not very consistent) ways. Some bits are altered by the results of certain instructions ("arithmetic" instructions generally - "data movement" instructions don't touch 'em) and the state of these bits is consulted by the "conditional jump" instructions. Your "jge" that wasn't working is an example of that. The "cmp" sets the flags (like a "sub" but the result isn't stored) and the "jge" jumps or not, depending on how the flags are set. There's a subtle issue that might concern you. "jg" (and "jl") are a signed comparison - that is, the overflow flag is checked as well as the carry flag. If the value in edx (I guess you're using esi now) had the high bit set (0x80000000 or bigger) it would be treated as "less" than zero and the jump would not be taken. Use "jb" (jump if below) and "ja" (jump if above) for unsigned comparisons. I don't think it'll be a problem in your code, but it's an important difference to know.
I'm tired, I'm rambling, those other bits are going to have to wait...
Best,
Frank