BASIC itself was written in Assembler, with the nearest thing to a procedure call was the 'JMP' instruction. It's amazing how any of such scale software was written in Assembler. See here https://github.com/microsoft/GW-BASIC
Most microprocessors include some sort of a procedure call and return instructions, such as CALL and RET on the 8080/Z-80/x86, as well as stack push and pop instructions.
RISC type processors can usually store the return address in a register and jump to an address stored in a register. On ARM you can also do an x86-like return with pop {pc}.
Many large programs such the first Unix kernel, and many video games, were written in assembly language.
My experience is that assembly language seems fine when you're writing it, but it's a pain when you go back some months later and try to read it. Good structure and comments help. I just read and wrote some RISC-V assembly language and it wasn't terrible, even though I'd never used RISC-V before. Writing assembly language makes you appreciate why (and how) programming languages exist.