To answer your question it's worth diving briefly into the instruction set of the architecture. Most instruction sets will contain 2 classes of jump instructions; the indirect jump and the direct jump. This includes call instructions and branch instructions as they generally all feature some kind of jump. The direct type will jump to a set location, i.e.
instruction pointer = value. Indirect jumps will perform the operation
instruction pointer = instruction pointer + value.
Since you want to be able to write in a higher level language you will likely be using a compiler, this saves you having to work out all these offsets. An option in the compiler is to have it assemble programs using indirect jumps exclusively. This mode is likely default because, as you're aware, there is an operating system to contend with and so you never know where your program is actually located. By avoiding direct jumps completely you no longer need to know where you are, just how far away you are.
Why have direct jumps in the first place?
They're faster, there's one less operation involved and often more. An indirect jump will need to look at the instruction pointer and add a number to it. Direct jumps then find themselves used in time critical situations as you'd often find in embedded applications such as microcontrollers or very low level OS and BIOS work.