If I have just one parameter in eax/rax and return value in eax/rax, why would I need a stack frame? It's not like any registers except eax/rax (and flags) are modified anyways. And that function doesn't call anything else that could modify eax/rax.
A call is a function as long as caller and callee agree on the calling convention. Non-exported functions don't necessarily need to adhere to platform ABI.
Generally you only push registers on stack when you need to modify more variables than what fit in your calling convention "thrashable" register set, or when you save register contents to call other function, or to push function call parameters on the stack.
I do embedded systems & low level drivers as my dayjob. Not a stranger to writing assembler routines.