Ah, I see what's happening... I think...
The "entrypoint" ld is looking for is "_start". You've got "_main", but "_main" isn't the "real" entrypoint. There's some "startup" code - in "crt0.o" or similar (apparently crt1.o, in this case) - which contains "_start", and which calls "_main", after doing some "housekeeping". Gcc links "crt?.o" (and libc) without being told to. This is the advantage to using gcc, even if there's no .c to compile - gcc "knows where the bodies are buried" (knows what need to be linked, and the path to it), and can invoke ld with the correct command line.
Doing "gcc -c main.c" creates "main.o" - fine so far. Nasm creates your "asm.o" - fine so far. But to link the whole mess together, we'd have to do "ld main.o asm.o /path/to/crt1.o" (I'd add "-o exename", too, or it'll produce "a.out"... I think) - possibly other stuff gets linked, too - I don't think so, in this case...
You can compile "main.c" separately, as you're doing, and then "gcc main.o asm.o [-o exename]" or you can do it in one step: "gcc main.c asm.o" ("asm.asm" has to be assembled to "asm.o" first, obviously).
You gave us all the information to figure this out in your first post - I just missed it. Sorry.
The above all applies to Linux. BSD is "like" Linux (or vise versa), and MacOSX is "like" BSD... except that there are some differences (like underscores). I *think* the above will work for MacOSX... except for some possible subtle differences - which I'll only know about if someone tells me. So I really appreciate your feedback!
Best,
Frank