The rax register is not preserved by the first syscall so simply setting al to 1 won't give you the right value for the next syscall in rax since it leaves all the upper bits untouched. The method which doesn't give you the bus error is one which re-populates all bits of rax.
Since write is meant to return the number of bytes actually written, that comes back in rax, ensuring that you will need to populate it fully for the next syscall. Support for this use of rax for the return code can be found on the Wikipedia calling convention page which states for the System V AMD64 ABI:
The calling convention of the System V AMD64 ABI[11] is followed on Solaris, GNU/Linux, FreeBSD, Mac OS X, and other UNIX-like or POSIX-compliant operating systems. The first six integer or pointer arguments are passed in registers RDI, RSI, RDX, RCX, R8, and R9, while XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 and XMM7 are used for floating point arguments. For system calls, R10 is used instead of RCX.[11] As in the Microsoft x64 calling convention, additional arguments are passed on the stack and the return value is stored in RAX.
It's also detailed in the System V Application Binary Interface, AMD64 Architecture Processor Supplement document in Appendix A.
In terms of fixing your code, you would be better off doing the full population sequence (sans unnecessary bit-shifts):
mov rax, 0x2000001
mov rdi, 0
syscall
to exit. In fact, I'd use that method for both system calls to simplify the source:
SECTION .text
global start
start:
mov rax, 0x2000004 ; syscall 4: write (
mov rdi, 1 ; fd,
mov rsi, Msg ; buffer,
mov rdx, Len ; size
syscall ; )
mov rax, 0x2000001 ; syscall 1: exit (
mov rdi, 0 ; retcode
syscall ; )
SECTION .data
Msg db `Hello, world!\n`
Len: equ $-Msg