The beginnings of a bootloader using GNU-based tools
Your code is well-commented. Other assembly answers on this site mention the importance of good comments: and yours are good.
An infinite loop at the end of the program is strange; instead I would have expected a ret or retf statement to return to the O/S shell which launched this program; but maybe that's different/excusable for what may in future evolve to become a boot-loader.
Writing to memory at 0xb8000 may or may not work depending on the current video mode. Here is a thread which discusses whether it's safe to assume 0xb8000 on computer startup (perhaps it is, but there are alternatives)
You code would be more compact (perhaps less readable) if you initialized entire words, instead of separate instructions for each byte; for example in the first program you could initialize ax and bx; and in the second program you could write 0x1E42 into the first word of video memory.
Using the 2nd method you'll probably start writing whole strings (not single characters) to the screen; the lods/stos/movs opcodes are useful for that. For example, you could do:

mov $0x1e, %ah # Write text attributes for the text right after
loop:
lodsb          # load byte from ds:si and increment si
cmp $0x00, %al # test for end-of-string
jz done
stosw          # store word (not byte) to es:di and increment di
jmp loop       # loop back to load-and-then-store next byte of the string
done:

For this kind of reason it's unconventional of you to use the ds register to point to video memory; I would have expected you to use the es register instead.
According to the GNU Assembler manual if you write %ds:0x00 then it will emit the ds prefix, which is unnecessary (I think that ds is the default segment for memory access); perhaps (based on the manual, I don't know) the syntax without the segment prefix is something like just 0x00 or perhaps 0x00(,1).


(I'm unable to give you feedback on the linker.ld section).