[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] Emulating MIPS self-examining code
From: |
Dmitry Antipov |
Subject: |
[Qemu-devel] Emulating MIPS self-examining code |
Date: |
Mon, 08 Feb 2010 17:26:33 +0300 |
User-agent: |
Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.7) Gecko/20100120 Fedora/3.0.1-1.fc12 Thunderbird/3.0.1 |
Hello,
I'm trying to emulate the following MIPS code (taken from the bootloader of my
system):
/* Initialize GOT pointer.
** Global symbols can't be resolved before this is done, and as such we
can't
** use any global symbols in this code. We use the bal/ move xxx,ra
combination to access
** data in a PC relative manner to avoid this. This code will
correctly set the
** gp regardless of whether the code has already been relocated or not.
** This code determines the current gp by computing the link time (gp -
pc)
** and adding this to the current pc.
** runtime_gp = runtime_pc + (linktime_gp - linktime_pc)
** U-boot is running from the address it is linked at at this time, so
this
** general case code is not strictly necessary here.
*/
/* Branch and link to get current PC in ra */
bal 1f
nop
.extern _GLOBAL_OFFSET_TABLE_
.word _GLOBAL_OFFSET_TABLE_ /* This contains the linked address of
the GOT */
/* The ra register now contains the runtime address of the above memory
location */
.word . - 4 /* This contains the link time address
of the previous word,
which is also what the link time
expected PC value is */
1:
move gp, ra /* Move current PC into gp register */
lw t1, 0(ra) /* Load linked address of the GOT into t1 */
lw t2, 4(ra) /* Load the link time address of the GOT storage
location into t2 */
sub t1, t2 /* Subtract t2 from t1. */
/* t1 now contains the difference between the link-time GOT table
address and the link time expected PC */
/* Add this difference to the current PC (copied into gp above) so that
gp now has the current runtime
** GOT table address */
add gp, t1 # calculate current location of offset table
Corresponding objdump output is:
...[skipped]
bfc306c4: 04110003 bal bfc306d4 <func+0x28>
bfc306c8: 00000000 nop
bfc306cc: bfc79d10 cache 0x7,-25328(s8)
bfc306d0: bfc306cc cache 0x3,1740(s8)
bfc306d4: 03e0e02d move gp,ra
bfc306d8: 8fe90000 lw a5,0(ra)
bfc306dc: 8fea0004 lw a6,4(ra)
bfc306e0: 012a4822 sub a5,a5,a6
bfc306e4: 0389e020 add gp,gp,a5
...[skipped]
bfc79d10 <_GLOBAL_OFFSET_TABLE_>:
bfc79d10: 00000000 nop
...[skipped]
This is a kind of self-examining code (bfc306cc..bfc306d0 is treated as data).
The problem
is that QEMU translates this (master?)piece into two translation blocks
bfc306c4..bfc306c8
and bfc306d4..bfc306e4, silently ignoring bfc306cc..bfc306d0 because there is
no way
to execute in that area. Due to this, 0(ra) at bfc306d8 can't be evaluated
correctly.
Is there any ideas on how to get such code emulated?
Dmitry
- [Qemu-devel] Emulating MIPS self-examining code,
Dmitry Antipov <=