Labels are followed by :
An = isn't a label, it defines a symbol as an assemble-time constant the way .set or .equ does. This is getting the assembler to calculate the length of the string for you, at assemble time.
. is the current position. Think of . as an implicit label at the start of this line. You could equivalently have put a str_end: label after the string and done len = str_end - str.
Why to use mov str(%rip), %rsi, when I can use movabs $str, %rsi?
Those aren't equivalent! mov str(%rip), %rsi would load 8 bytes from that address, getting the string data into a register. But you need a pointer to the string in a register as an arg for a write(int fd, void *buf, size_t len) system call. Try it in a debugger and/or strace and watch it fail.
That's why the movabs in this code uses $str, to get the address as a 64-bit immediate.
However, that's the worst way to put a label/symbol address into a register. movabs with an 8 byte immediate amounts to a 10-byte instruction total, and being absolute it needs runtime fixups in a PIE executable or library (ELF shared object) when the loader chooses an actually base address for the executable.
You actually want LEA str(%rip), %rsi (7 bytes), or in a non-PIE Linux executable where static addresses fit in the low 31 bits of address space, mov $str, %esi.