I would like to begin writing ARM assembler and running it on the iPhone.
This is not with the intent of using in an app to be released to the app store - Basically I would like to solve problems on ProjectEuler using ARM and the iPhone, just for hobby and educational purposes.
How can I go about doing this? I have not been able to come up with a way get a project running using any hand written arm.
I haven't been able to find any information about how to write assembly code specifically for the iPhone, but like the other people said here, you can either:
1) write inline asm statements in C/C++/ObjC code, or
2) write standalone assembly functions in a '.s' file and simply add it in your XCode sources, or
3) write standalone assembly functions for an external assembler such as NASM. You write assembly code in a '.s' file and generate a '.o' object file using NASM and link the object file with your project in XCode.
So if you are just trying to write a few assembly instructions then inline assembler would be the easiest way, but if you plan on writing several assembly functions then I'd recommend a standalone assembly file. And if you plan on writing many assembly functions with macros and want cross-platform compatibility, etc, then I'd recommend using NASM to compile your assembly code into an object file. Because I am using the XCode gcc assembler and it is quite lacking compared to NASM. You can get NASM for free at http://www.nasm.us/
Once you have setup your assembler environment, you need to learn how to write ARM Assembly code! Because the iPhone (and many other portable devices and smartphones) use the ARM instruction set. There is a very good but old intro to ARM assembly at http://www.coranac.com/tonc/text/asm.htm.
When it comes to assembly programming, the official instruction set reference manual is usually the main source of information for everything you will write, so you should go to the ARM website and download the ARM and Thumb-2 Quick Reference Card (6 pages long) as well as the 2 full documents for your exact CPU.
For example, the iPhone 3GS and iPhone 4 both have an ARMv7-A Cortex-A8 CPU, so you can download the ARM Architecture Reference Manual ARMv7-A and ARMv7-R Edition (2000 pages long) that tells you exactly which instructions are available and exactly how they work, and the Cortex™-A8 Technical Reference Manual that explains the instruction timing, etc for your specific CPU.
You can use gcc to make asm inlines with __asm__, or just get a gnu as for arm and write code in separate files. You should have no problems with later linking them up to your project, but I'd suggest you to use c/Objective-C code to wrap up your asm stubs, as writing the whole iPhone application in assembler is somewhat hard (you need to be pretty good in ObjC runtime internals).
You might be interested in using custom Makefiles, however Xcode projects should be sufficient for most of the taks too.
Note also that there is nothing wrong with including assembly in app store submissions. It's only using frameworks that are not public they frown on.
They don't care how the binary is generated as long as it works, looks decently OK, and follows the aforementioned rule.
So, here is a quick description of how to actually include ARM asm code into an Xcode project, this is tested in Xcode versions up to 4.3. For my specific project, I wanted to define a function in ASM code saved with a filename like "decode_arm.s". I already have a C implementation of the same function that gets compiled when run under the simulator, so the conditional cpp logic here ensures that the ARM ASM code is only compiled into the project when actually compiling for the device.
// This file implements the following C functions for the ARM platform.
// Both ARM6 and ARM7 devices are supported by this implementation.
//
// maxvid_decode_c4_sample16()
#if defined(__arm__)
# define COMPILE_ARM 1
# if defined(__thumb__)
# define COMPILE_ARM_THUMB_ASM 1
# else
# define COMPILE_ARM_ASM 1
# endif
#endif
#if defined(COMPILE_ARM)
# define USE_GENERATED_ARM_ASM 1
#endif // COMPILE_ARM
#if defined(USE_GENERATED_ARM_ASM)
.section __TEXT,__text,regular
.section __TEXT,__textcoal_nt,coalesced
.section __TEXT,__const_coal,coalesced
.section __TEXT,__picsymbolstub4,symbol_stubs,none,16
.text
.align 2
.globl _maxvid_decode_c4_sample16
.private_extern _maxvid_decode_c4_sample16
_maxvid_decode_c4_sample16:
# args = 0, pretend = 0, frame = 0
# frame_needed = 1, uses_anonymous_args = 0
stmfd sp!, {r4, r5, r6, r7, lr}
add r7, sp, #12
stmfd sp!, {r8, r10, r11}
(ASM CODE HERE)
ldmfd sp!, {r8, r10, r11}
ldmfd sp!, {r4, r5, r6, r7, pc}
.subsections_via_symbols
#else
// No-op when USE_GENERATED_ARM_ASM is not defined
#endif
Related
I have a working Yocto build system based on the rocko branch that is generating images for an ARM-based target board. One of the chips on this board is a small ARM-based micro-controller that is separate to the main CPU. It needs to be loaded with a firmware image that I have to build.
It would be easy to make a recipe to build this microcontroller firmware. It requires an ARM cross compiler and then some special compiler options to control the code generation (for cortex-m4 + thumb etc). The trouble is, if I setup a normal recipe, it will assume that I'm building something for the target ARM architecture, which is a different type of ARM needing different code generation options. I can of course have the firmware Makefile override the cross-compile environment that is provided for the target system and have the Makefile just produce the binary firmware image.
But this will result in a package that is nominally for the target ARM architecture, but which contains a binary blob intended to be flashed onto a chip on the target board.
So my question is, how should I make a recipe for firmware that will execute on a totally different architecture to the MACHINE that the yocto build is ultimately for?
It seems like I need to create a recipe that builds specially for the micro-controller and is therefore different in some way to normal target recipes.
Multiconfig may help you. One of the use case is that you want to build image for board which consists of FPGA and ARM core, this is somehow similar to your use case.
Quoting release notes of morty (2.2), it was introduced there:
Basic support for multi-configuration builds. For example, this enables building for more than one MACHINE at a time, which may be useful if you have a board with two separate SoCs on it, each with their own OS, but you want to target both in the same build.
I didn't try it yet, but the documentation for rocko is here: https://www.yoctoproject.org/docs/2.4/mega-manual/mega-manual.html#platdev-building-targets-with-multiple-configurations
You basically define two machine configuration files, define them in BBMULTICONFIG variable and run bitbake with multiconfig:<configuration>: prefix for target when needed.
You need to create a bbclass, that will change the necessary variables for you, and inherit it in your recipe. Let's take as an example nativesdk.bbclass. Your newarch.bbclass file will look something like:
CLASSOVERRIDE = "class-newarch"
PACKAGE_ARCH = "newarch"
PACKAGE_ARCHS += "newarch"
TARGET_ARCH = "newarch"
TARGET_CC_ARCH = "newarch"
TARGET_LD_ARCH = "newarch"
TARGET_AS_ARCH = "newarch"
TARGET_CPPFLAGS = "..."
TARGET_CFLAGS = "..."
TARGET_CXXFLAGS = "..."
TARGET_LDFLAGS = "..."
CPPFLAGS = "..."
CFLAGS = "..."
CXXFLAGS = "..."
LDFLAGS = "..."
I'm making project generated with STM32CubeMX for stm32f469i-disco.
I have based setup on "FreeRTOSconfig.h" from "Demonstration" project in STM32CubeFWF4V1.16.0 repo. Fresh project from CubeMX compiles without problems, but after adding STemWin lib "STemWin532_CM4_OS_Keil_ot.lib" I get the error
"..........\Middlewares\ThirdParty\FreeRTOS\Source\portable\RVDS\ARMCM4F\port.c(507):
error: A1586E: Bad operand types (UnDefOT, Constant) for operator ("
Interesting fact is that "Demonstration" compiles without this error.
How do I get the project configured:
In CubeMX:
Add periphs needed: DMA2D, DSIHost, FMC etc.
Add BSP drivers for touchscreen etc.
Now, it copiles without problems.
Clone "Clock Configuration" based on "Demonstations"
In "Configuration" tab I clone all configuration based on code from "Demonstrations"
Then in Keil:
5. I update Include Path in target options.
Add all STemWin files and when i try to compile:
"...Bad operand types..."
When I disable freertos in CubeMX and add non-OS STemWin lib it compiles without problems.
When I try to compile non_OS STemWin lib with FreeRTOS enabled, it fails with the same message.
What have I tried to do?
Update port.c. Nothing changed.
Am I missing something while creating project?
After spending 2 days to find out what might be the reason for this error, I just found it and my project now compiles with FreeRTOS enabled and all the other sources used initially. Well, it's apparently a recursive include for stm32f4xx_hal.h file. I have added some modules from the demo package and those have some dependencies. Because I wanted to strip out some functions from some modules, I have manually added the includes/resources for the functions needed, which has contributed to that error, as I did not add any guards to my includes.
The offending line was in port.c file, and the error was because of a wrong constant value passed to the assembly line 483: mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
Replacing configMAX_SYSCALL_INTERRUPT_PRIORITY with any numeric value has helped in compiling the code, but I thought I should not leave it like that and it would be much better if I found out the reason for the problem.
More could be found here:
https://community.st.com/thread/44751-portc483-error-a1586e-bad-operand-types-undefot-constant-for-operator
I got a same problem while building a Nucleo-F401RE board firmware with CubeMX 4.25.
This problem started just after setting LL driver use (Low-Level driver) instead of HAL in a CubeMX setting dialog.
I think this problem is from complicit in C definition of header file.
Including LL driver header may change __NVIC_PRIO_BITS definition in somewhere.
#ifdef __NVIC_PRIO_BITS
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#define configPRIO_BITS 4
#endif
#define configMAX_SYSCALL_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
Changing __NVIC_PRIO_BITS to 4 in a generated source code will solve the problem.
/* mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY */
mov r0, #(configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - 4))
I am playing around a bit bit with Microsofts ELL library/compiler to deploy a simple learning algorithm to a micro controller. But my knowledge regarding embedded development has been better in the past. The Problem is the following:
ELL creates an LLVM IR file and a C Header file from a CNTK machine learning model (There are no pure c/c++ files). So far so good. Now I can use the IR to tell llc to make an assembler or object file for the desired target from it (ARM Cortex M4 in my case).
So I end up with a header file model.h and an assembler file model.s or an object file model.o.
Now I want to include this model with the header and the precompiled model in my embedded project.
For developing, I use the Bosch XDK, the IDE is basically Eclipse.
So, is there a way, that I can include the precompiled model in my code? When yes, how? And how do I correctly include it in Eclipse? Or do I have to do further steps? I also thought about making a static library out of the object file, but I do not have any experience on this and my tries did not end successfully so far. Thanks for your kind help.
If you make a static library from the object file, the linker will simply extract the object file and link it. That is an unnecessary step, you can add the object file to the linker command line directly. Alternatively add the .s source file to your project - the default build rules should identify it as an assembly language file and invoke the assembler rather then the compiler.
I'm trying to convert a program and its plugin from custom Makefiles to CMake, with minimal changes to the code.
Both the plugin and the app share some code; #ifdef ... #else ... #endif blocks are used where there are differences, and I'm certain the code is compiled with the correct defines. The shared code includes a class called ToolImage. When the code is compiled for the app, the ToolImage constructor uses a different resource path than when it is compiled for the plugin.
#ifdef THE_APP
ToolImage::ToolImage(const wxString& name, bool full_path_given):wxImage(full_path_given?name:
(wxGetApp().GetResFolder() + _T("/bitmaps/") + name + _T(".png")), wxBITMAP_TYPE_PNG)
#else
ToolImage::ToolImage(const wxString& name, bool full_path_given):wxImage(full_path_given?name:
(theApp.GetResFolder() + _T("/bitmaps/") + name + _T(".png")), wxBITMAP_TYPE_PNG)
#endif
{
...
}
When the program and its plugin have been compiled with the custom Makefiles, everything works as expected. When both have been compiled with CMake, using a series of CMakeLists.txt files I created, there is an issue: the plugin isn't able to load the bitmaps for its toolbar.
I tracked the problem to the ToolImage class. The line number given by gdb tells me that the plugin is using the wrong constructor. strace tells me the same thing (the plugin is looking for its bitmaps in the app's resource dir rather than in the plugin's resource dir). To ensure that I didn't have the defines screwed up, I put a #error in ToolImage.cpp, inside the part of the #ifdef that should only be compiled for the app - and the plugin still compiled without error. This tells me that the plugin is compiling with the correct code. Since it is using the wrong path, I think it is using the class and constructor compiled into the program instead of its own.
How do I ensure that the plugin uses its own ToolImage class instead of the one in the app?! I don't own the project and don't want to make massive changes merely to support building with a different build system.
Using the precompiler to create two versions of a class seems like a poor choice to me. If I must make changes to the code, do you have suggestions for a workaround?
For the sake of experiment, I'd add -fvisibility=hidden when building theapp, to all or maybe to some specific sources. This should hide application's ToolImage from the plugin.
It is not a universal method, as in many cases plugins do use different symbols from the main executable.
I fixed this by adding the linker flag -Wl,-Bsymbolic-functions in the CMakeLists.txt:
set_target_properties( heekscnc PROPERTIES LINK_FLAGS -Wl,-Bsymbolic-functions )
I am writing a reusable static library for the iPhone, following the directions provided here.
I want to use minizip in my library internally, but don't want to expose it to the user.
It should be possible for the user to include minizip themselves, possibly a different version, and not cause clashes with my "inner" minizip version.
Is this possible?
Edit:
I've tried adding -fvisibility=hidden to additional compiler flags for minizip files and changing functions to be __private_extern__ and __attribute__((visibility("hidden"))), but it still seems to produce defined external symbols:
00000918 T _unzOpen
0000058e T _unzOpen2
00001d06 T _unzOpenCurrentFile
00001d6b T _unzOpenCurrentFile2
...
Edit #2:
Apparently the symbols marked with these annotations are only made private by the linker, which never happens when Xcode builds the sources, since it adds the -c parameter ("Compile or assemble the source files, but do not link.")
You could rename all exported symbol from minizip with objcopy.
something like
objcopy -redefine-sym=minizip.syms yourstaticlibray.a
and minizip.syms
_unzOpen _yourownprefix_unzOpen
_unzOpen2 _yourownprefix_unzOpen2
... ...
No clash if an executable is linked with an other minizip.a and yourstaticlibray.a, and because you renamed all the symbol in yourstaticlibray.a your call inside yourstaticlibray.a to minizip will use the prefixed symbol, and not the unzOpen one.
Since static library is nothing more than a set of .o files (which are not linked yet, as you have mentioned), the only way to completely hide presence of minizip from the outside world is to somehow compile minizip and your library together as a single compilation unit and make minizip functions/variables static.
You could have a look at how does SQLite do the "amalgamation" process which turns library source code into single .c file for further compilation: The SQLite Amalgamation.
As a bonus you'll get better optimization (really recent GCC and Binutils are able to make link-time optimizations, but this functionality is not released yet).