Labels are addresses (and note that function names in high level languages are labels basically).
loop:
nop
nop
jump loop
this allows you to write code that has two features. One is, what is the address of loop, is it 0x12345 is it 0x8000, etc. Second is if my pseudo-code instruction set here does the jump instruction operate on fixed addresses so it would need to know 0x12345 or 0x8000 to fully encode the instruction or is it relative where without labels the programmer would have to count instruction bytes. If nops were one byte each and the jump itself is relative and let's say three bytes and the pc offset is relative to the end of the instruction then you would have to say jump -5 in your code then if you added or removed instructions in the loop you would have to re-calculate the jump offsets with no mistakes.
Another case, that is again an address thing, is for external references:
fun:
call more_fun
...
If you are in modern times where you can have more than one file of source code become objects and then get linked. (some tools still support this, was more common when I started to be able to have a single asm file with .org etc in there and no external references only forward vs backward references) Then you can have external references, whether the instruction set uses an absolute or relative addressing in order to complete the creation of the machine code for this call that address needs to be resolved. So using a label makes this much easier on the programmer and as with local references the tools can compute all of these offsets or addresses for you.
Edit
.thumb
nop
nop
nop
loop:
nop
nop
nop
b loop
Disassembly of section .text:
00000000 <loop-0x6>:
0: 46c0 nop ; (mov r8, r8)
2: 46c0 nop ; (mov r8, r8)
4: 46c0 nop ; (mov r8, r8)
00000006 <loop>:
6: 46c0 nop ; (mov r8, r8)
8: 46c0 nop ; (mov r8, r8)
a: 46c0 nop ; (mov r8, r8)
c: e7fb b.n 6 <loop>
so the second column of numbers (both columns are in hex) is the machine code. You can see that there is no machine code for the label, it is just a label a marking on a box it describes the thing on the box is not the contents of it's own box.
And I will just tell you the branch to loop encoding the lower bits are an offset and there are a lot of ones in that value because it is a negative number (pc-relative branch backward).
The above addresses are unlinked.
One file:
.thumb
nop
nop
loop:
bl more_fun
b loop
Another:
.thumb
.thumb_func
.globl more_fun
more_fun:
bx lr
unlinked we see the disassembly of the call (bl branch link in this instruction set) has basically a placeholder for an offset.
Disassembly of section .text:
00000000 <loop-0x4>:
0: 46c0 nop ; (mov r8, r8)
2: 46c0 nop ; (mov r8, r8)
00000004 <loop>:
4: f7ff fffe bl 0 <more_fun>
8: e7fc b.n 4 <loop>
once linked
Disassembly of section .text:
00001000 <loop-0x4>:
1000: 46c0 nop ; (mov r8, r8)
1002: 46c0 nop ; (mov r8, r8)
00001004 <loop>:
1004: f000 f801 bl 100a <more_fun>
1008: e7fc b.n 1004 <loop>
0000100a <more_fun>:
100a: 4770 bx lr
the bl instruction has changed to have the pc relative offset.
All of this magic is done by the tools and we only have to keep track of labels. This is the same for the instructions themselves we can use human readable/writeable mnemnonics:
bx lr
instead of machine code:
0x4770
In our programs.