I have compiled a rudimentary virtual machine loop using GCC's labels as
values extension on Debian AMD64 (Linux 2.6.16). I have isolated the entry
and exit code (I'm compiling at -O0 and there's forced register pressure):
00000000004007ae <vm_loop>:
4007ae: 55 push %rbp
4007af: 48 89 e5 mov %rsp,%rbp
4007b2: 41 57 push %r15
4007b4: 41 56 push %r14
4007b6: 41 55 push %r13
4007b8: 41 54 push %r12
4007ba: 48 83 ec 20 sub $0x20,%rsp
4007be: 48 89 7d c8 mov %rdi,0xffffffffffffffc8(%rbp)
--------------------------------------------------------------------------
4007c2: 48 83 7d c8 00 cmpq $0x0,0xffffffffffffffc8(%rbp)
4007c7: 0f 85 00 01 00 00 jne 4008cd <vm_loop+0x11f>
...
...
400a83: eb 00 jmp 400a85 <vm_loop+0x2d7>
--------------------------------------------------------------------------
400a85: 48 83 c4 20 add $0x20,%rsp
400a89: 41 5c pop %r12
400a8b: 41 5d pop %r13
400a8d: 41 5e pop %r14
400a8f: 41 5f pop %r15
400a91: c9 leaveq
400a92: c3 retq
I have concatenated the entry and exit code in dynamic (malloc'd) memory:
55 48 89 e5 41 57 41 56 41 55 41 54 48 83 ec 20 48 89 7d c8 \
48 83 c4 20 41 5c 41 5d 41 5e 41 5f c9 c3
The vm_loop has function signature "void vm_loop(unsigned char* code)". I
have duplicated this function declaration as variable fn:
void (*fn)(unsigned char*); and assigned fn to this area of memory.
main() calls fn(<dummy value>) before finally returning [this fragment,
which starts at a final printf("\n"), is evidence of this]:
...
40078f: e8 bc fd ff ff callq 400550 <putchar@plt>
400794: 48 8d 45 d8 lea 0xffffffffffffffd8(%rbp),%rax
400798: 48 89 45 e0 mov %rax,0xffffffffffffffe0(%rbp)
40079c: 48 8b 05 15 0a 10 00 mov 1051157(%rip),%rax # 5011b8 <_DYNAMIC+0x190>
4007a3: 48 89 c7 mov %rax,%rdi
4007a6: 48 8b 45 e0 mov 0xffffffffffffffe0(%rbp),%rax
4007aa: ff d0 callq *%rax
4007ac: c9 leaveq
4007ad: c3 retq
The code segfaults instead of silently returning. Any tips for what I've
overlooked in the direct execution of PIC within dynamic memory?
Many thanks,
Adam
> The code segfaults instead of silently returning. Any tips for what I've
> overlooked in the direct execution of PIC within dynamic memory?
Perhaps you neglected to add PROT_EXEC to the page permissions?
(on x86, PROT_READ implies PROT_EXEC; not so on AMD64).
Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
> Adam Warner <use...@consulting.net.nz> writes:
>
>> The code segfaults instead of silently returning. Any tips for what I've
>> overlooked in the direct execution of PIC within dynamic memory?
>
> Perhaps you neglected to add PROT_EXEC to the page permissions?
> (on x86, PROT_READ implies PROT_EXEC; not so on AMD64).
Indeed I had to mprotect the dynamic memory. Once I learned how to use gdb
and ddd to single step through instructions I found I was also calling the
wrong area of memory! With that fixed the code terminates successfully.
Many thanks,
Adam