it's behavior depends on the operating system. In UNIX, it would initially malloc a block of memory, then read from the device using a system call. Subsequent calls to getchar() return characters from this internal buffer until it's empty, it then makes another system call.
You'd never write getchar in assembler. It's more portable, quicker, less error prone and faster at runtime writing it in C compared to assembler.