Wednesday, May 1, 2013

how to write position independent code

writing position independent code -- x86 Windows.
AMD64 is much easier -- most code is naturally position independent
ARM32 is also viable, but not shown here.

I'm not an expert, but this weekend I finally wrote
some position independent code.
Accesses of global data incur relocations.
jmp and call do not.


So wrap data in functions. Including imports.
Possibly collect all your data together in one struct.
struct globals_t { ... } globals;
globals_t* GetGlobals();


Here is a working example.
Notice the lack of .reloc in link /dump.


We need the custom import library.
Without it, when the linker finds __imp__printf in msvcrt.lib,
it complains about the duplicate _printf.
By claiming that printf is data, the import .lib only has __imp__printf and no _printf.


  link /lib /def:msvcrt.def /machine:x86 
  ml -c 4asm.asm 
  cl  4.c -link 4asm.obj -entry:Entry -subsystem:console -incremental:no -nod .\msvcrt.lib 
  link /dump 4.exe
  .\4.exe


4.c:

int __cdecl printf(const char*, ...);
void * GetImageBase(void);

extern const char string[] = "%p\n";
char* p_string(void);

int Entry()
{
printf(p_string(), GetImageBase());
return 0;
}



4asm.asm:

.model flat
.686


_text segment


public _GetImageBase
_GetImageBase proc
  call @F
@@:
  pop eax
  sub eax, imagerel $ - 1
  ret
_GetImageBase endp



IMPORT macro name
externdef __imp__&name:dword, _&name:proc
_&name proc
  call _GetImageBase
  add eax, imagerel __imp__&name
  jmp dword ptr [eax]
_&name endp
  endm


DATA macro name
externdef _&name:byte, _p_&name:proc
_p_&name proc
  call _GetImageBase
  add eax, imagerel _&name
  ret
_p_&name endp
  endm


IMPORT printf
DATA string


_text ends
end



msvcrt.def:
EXPORTS
printf DATA


No comments:

Post a Comment