Yeah, you want "position independent code". The alternative, as Keith points out, is a "relocation table", which you would get with a linkable object format. Windows ".dll"s have a "preferred" address, but if it needs to be loaded elsewhere, it has a relocation table, and can be "relocated" to another address (some "fudge factor" is added to all the fixed addresses). Linux shared libraries lack a relocation table, and have to be able to run at any address. From something Keith showed us the other day, Mac compilers apparently generate position independent code by default (dunno why).
But if you're going to load at 100h one time, and 8000h another, how is the "calling" code going to find it? No doubt, you can find a solution to that, but by the time you're done, you'll have reinvented the linkable file format. Maybe you'll come up with a better one!
If you've got multiple variables, the "call and pop the address" trick will get tedious. I'd do something like:
get_vars:
call got_vars
vars:
_hello db "hello world", 0
_goodbye db "goodbye world", 0
_answer dd 42
...
and for convenience:
%define hello ebp + _hello - vars
%define hello ebp + _goodbye - vars
%define hello ebp + _answer - vars
...
Then you can do...
jmp get_vars
got_vars:
pop ebp
mov ebx, [answer]
But they don't have an "offset", so you'll have to use "lea".
lea esi, [hello]
call print_it ; assuming "print_it" takes its parameter in esi
If a routine takes its parameter on the stack, you'll have to...
lea eax, [goodbye]
push eax
call ...
; clean up stack, or not...
...
I don't know if that'll be any help to you. PITA to set up, but it goes okay after that... May not be appropriate for what you're doing.
Best,
Frank