Hello squeak-dev,
in the last weeks, based on my simple code examples, I tried to copy the BochsIA32Plugin structures and adapt it to ARMulator/libopcodes. So far, I am able to run code sequentially with memory bounds checks. The (copied) test testExecutionTrap and testResetCPU are green. The testCallTrap might also be green, once I figured out what the correspondent of the IA32 call opcode in ARM is.
The code for library tests and the c-part of the plugin is accessible on Github[1].
For these tests, I implemented an alternative memory interface (armulmem.c). The problem with bounds checking and especially execution bounds was the prefetching emulation: Whenever an instruction is executed, the next two words are read from memory, too. Because of that, it is not possible to quit with the appropriate error code in the memory interface. The current solution uses a custom Software Interrupt (0x200000). The memory interface returns the 'SWI 0x200000' opcode whenever it is asked for an instruction at an invalid address. This is implemented in ARMul_ReLoadInstr. For random memory access, the corresponding functions are GetWord and PutWord, which stop simulation immediately.
An interesting detail about the ARMulator is, that it is also the base for the ARM-Emulator used in Skyeye, beside being used in gdb. In case anybody wants to try using my code examples, it is very important to compile libsim.a with -DMODET (which is default on my system) or disabling that flag in GdbARMPlugin.h. That little flag took me at least two days, because it changes multiple offsets in the main struct ARMul_State.
What still is not included on that site is reporting. The Bochs test cases show that there should be string-errors. The ARMulator does not provide those strings, and since so far this is the only error, I put no additional effort into that.
The next step is getting the testNfib* green. These compute the Fibonacci function for different arguments. For that, I need to understand the ARM ABI[2].
I'd be grateful if anybody can recommend a more abstract source for the ARM ABI. Enjoy your evening, Lars
[1] https://github.com/mas7ermind/gdb-arm-tests https://github.com/mas7ermind/squeakvm-armulator-plugin [2] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ihi0036b/index.h...
Hi Lars:
Thanks for the update!
On 09 Jul 2012, at 21:28, Lars wrote:
in the last weeks, based on my simple code examples, I tried to copy the BochsIA32Plugin structures and adapt it to ARMulator/libopcodes.
Just to refresh everyone's memory, the BochsIA32Plugin allows to simulate x86 code. And the new ARM plugin will enable us to simulate ARM code to debug it inside the Smalltalk image.
So far, I am able to run code sequentially with memory bounds checks. The (copied) test testExecutionTrap and testResetCPU are green. The testCallTrap might also be green, once I figured out what the correspondent of the IA32 call opcode in ARM is.
Did you notice this PDF already? http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf
Especially section 5 should be interesting. Section 5.3 gives also a minimal example how a call typically is done.
My understanding so far is, that the branch-link instruction is what CALL is on x86. As I understand the difference, it is mainly that CALL will put the return address on the stack, while ARM got the link register for that. Otherwise, both will do the jump to the given address. x86's return will then do the inverse, it expects the stack pointer to be at the position of the return address, will pop it, and use it to jump back.
On ARM, a simple jump with the link register should suffice.
More tricky will be to get the calling conventions right, thus handling of parameters and return values. The basics are discussed in that document too. Not sure where to find other example, guess the easiest and most informative will be to ask gcc to give you the assembler output for C code.
For these tests, I implemented an alternative memory interface (armulmem.c). The problem with bounds checking and especially execution bounds was the prefetching emulation: Whenever an instruction is executed, the next two words are read from memory, too. Because of that, it is not possible to quit with the appropriate error code in the memory interface.
To give some more details: My understanding is that Eliot used the bounds checks to be confident that he never executes anything outside the explicitly allocate ByteArray with the assembled code. To have some protection during simulating the machine code, and be guarded against off-by-one errors, jumps to random addresses, etc.
The current solution uses a custom Software Interrupt (0x200000). The memory interface returns the 'SWI 0x200000' opcode whenever it is asked for an instruction at an invalid address. This is implemented in ARMul_ReLoadInstr. For random memory access, the corresponding functions are GetWord and PutWord, which stop simulation immediately.
I like the solution with the custom software interrupt, thanks for changing that!
An interesting detail about the ARMulator is, that it is also the base for the ARM-Emulator used in Skyeye, beside being used in gdb. In case anybody wants to try using my code examples, it is very important to compile libsim.a with -DMODET (which is default on my system) or disabling that flag in GdbARMPlugin.h. That little flag took me at least two days, because it changes multiple offsets in the main struct ARMul_State.
Would be good if people try to look at the code, compile it, and report all the problems you find. So, that we can make sure that we have something that is portable in the end. Lars works on Windows and Linux as far as I remember.
Best regards Stefan
Hi Stefan,
Am 09.07.2012 22:04, schrieb Stefan Marr:
Hi Lars:
Thanks for the update!
On 09 Jul 2012, at 21:28, Lars wrote:
in the last weeks, based on my simple code examples, I tried to copy the BochsIA32Plugin structures and adapt it to ARMulator/libopcodes.
Just to refresh everyone's memory, the BochsIA32Plugin allows to simulate x86 code. And the new ARM plugin will enable us to simulate ARM code to debug it inside the Smalltalk image.
So far, I am able to run code sequentially with memory bounds checks. The (copied) test testExecutionTrap and testResetCPU are green. The testCallTrap might also be green, once I figured out what the correspondent of the IA32 call opcode in ARM is.
Did you notice this PDF already? http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf
Especially section 5 should be interesting. Section 5.3 gives also a minimal example how a call typically is done.
My understanding so far is, that the branch-link instruction is what CALL is on x86. As I understand the difference, it is mainly that CALL will put the return address on the stack, while ARM got the link register for that. Otherwise, both will do the jump to the given address. x86's return will then do the inverse, it expects the stack pointer to be at the position of the return address, will pop it, and use it to jump back.
On ARM, a simple jump with the link register should suffice.
More tricky will be to get the calling conventions right, thus handling of parameters and return values. The basics are discussed in that document too. Not sure where to find other example, guess the easiest and most informative will be to ask gcc to give you the assembler output for C code.
Thank you.
For these tests, I implemented an alternative memory interface (armulmem.c). The problem with bounds checking and especially execution bounds was the prefetching emulation: Whenever an instruction is executed, the next two words are read from memory, too. Because of that, it is not possible to quit with the appropriate error code in the memory interface.
To give some more details: My understanding is that Eliot used the bounds checks to be confident that he never executes anything outside the explicitly allocate ByteArray with the assembled code. To have some protection during simulating the machine code, and be guarded against off-by-one errors, jumps to random addresses, etc.
The current solution uses a custom Software Interrupt (0x200000). The memory interface returns the 'SWI 0x200000' opcode whenever it is asked for an instruction at an invalid address. This is implemented in ARMul_ReLoadInstr. For random memory access, the corresponding functions are GetWord and PutWord, which stop simulation immediately.
I like the solution with the custom software interrupt, thanks for changing that!
An interesting detail about the ARMulator is, that it is also the base for the ARM-Emulator used in Skyeye, beside being used in gdb. In case anybody wants to try using my code examples, it is very important to compile libsim.a with -DMODET (which is default on my system) or disabling that flag in GdbARMPlugin.h. That little flag took me at least two days, because it changes multiple offsets in the main struct ARMul_State.
Would be good if people try to look at the code, compile it, and report all the problems you find. So, that we can make sure that we have something that is portable in the end. Lars works on Windows and Linux as far as I remember.
Best regards Stefan
I work on Windows (7). Linux I only use for cross-compiling (e.g. the Fibonacci function). It took me quite some time to get a working environment, so if anybody has problems there, I know your pain and am gladly trying to help.
All the best, Lars
vm-dev@lists.squeakfoundation.org