This instalment of “A look under ARC’s hood” is all about the new @autoreleasepool directive. LLVM tells us that the semantics of autorelease pools has changed with LLVM 3.0 and in particular, I thought it might be interesting to see what ARC is doing when it comes to these.
A look under ARC’s hood – Episode 3
February 1st, 2012UIImageOrientation / EXIF orientation sample images
January 30th, 2012Whilst I was doing some work with images recently I was in desperate need for some sample images which were tagged with the EXIF orientation flag for each of the 8 orientations which are supported by UIImage in its UIImageOrientation metadata. I couldn’t find any already out there, so I made my own. And now I’m posting them here for anyone who might also find this useful. I now have these saved on my iPhone and use them in apps as test images.
How to visualise affine transforms when drawing with Quartz 2D.
January 30th, 2012I had been struggling with some code that I had to rotate an image whilst drawing it so I decided to sit down and work out a nice way to visualise it as I hadn’t seen anything out there really that explained it very well. This is what I came up with…
GiffGaff: Great for iPad!
November 12th, 2011I’ve heard about GiffGaff from a lot of people but it was only when I realised how good it would be for my iPad that I decided to give it a go. So I got a SIM, topped up £10 and now I can spend just 20p each day and get 20MB of data! It’s great for my iPad because I can use it whilst out and about and just pay for each day that I want mobile data, which is quite rare for me really.
So if you’ve got an iPad and want cheap data for it then go grab a GiffGaff SIM and away you go!
I came across another interesting compiler bug today. I’m not going to go into too much detail about it, but the problem code is this:
void a() {
int a = 0;
int b = 0;
__asm__("\n"
"\tmov %0, 0\n"
"\tldr %0, %1\n"
"\tmov %1, 0\n"
: "=r"(a), "+m"(b)
);
}
To break that down a bit, the function is doing this:
-
int a = 0; int b = 0;Initialise a couple of variables and set them to 0.
-
__asm__("\n" "\tmov %0, 0\n" "\tldr %0, %1\n" "\tmov %1, 0\n" : "=r"(a), "+m"(b) );Then perform some inline assembly using the variables. This just puts 0 into the register that will hold our ‘a’ variable, then loads the value of ‘b’ into ‘a’, then sets ‘b’ to 0.
This is of course a contrived example, but it illustrates the bug. The output assembly from LLVM-GCC or clang is (for ARM architecture):
.globl _a
.align 2
.code 16
.thumb_func _a
_a:
sub sp, #8
movs r0, #0
movt r0, #0
str r0, [sp, #4]
str r0, [sp]
mov r0, sp
@ InlineAsm Start
mov r0, 0
ldr r0, [r0]
mov [r0], 0
@ InlineAsm End
str r0, [sp, #4]
add sp, #8
bx lr
The interesting bit is the inline assembly. You’ll notice that it’s doing something very stupid. It’s choosing the same register for both operands (it’s choosing r0). This is completely wrong, and will lead to a runtime crash in this case due to the dereference of 0.
I did a bit of hunting and it appears to be a problem in generating the LLVM bytecode as the problem manifests itself before the LLVM bytecode is compiled down into instructions, like so:
define void @a() nounwind ssp {
%a = alloca i32, align 4
%b = alloca i32, align 4
store i32 0, i32* %a, align 4
store i32 0, i32* %b, align 4
%1 = call i32 asm "\0A\09mov $0, 0\0A\09ldr $0, $1\0A\09mov $1, 0\0A", "=r,=*m,*m"(i32* %b, i32* %b) nounwind, !srcloc !0
store i32 %1, i32* %a, align 4
ret void
}
You can see here that the ‘%a’ (i.e. variable ‘a’) is never referenced, only ‘%b’ (i.e. variable ‘a’). This is not what we’d expect at all given we’re referencing both variables in the code.
I found this quite interesting
.
[Update]
I’ve actually found out that this isn’t a bug! That’s good news, right? It’s quite a subtle thing, but the heart of the problem can be explained after understanding the modifiers to operands on inline assembly. The problem is that we’re not specifying that ‘a’ is clobbered early. In the assembly, we’re writing to it before reading we’ve finished using all input operands (only ‘b’ in this case) so we’re meant to mark it like that. It’s just luck that GCC does the right thing – Apple’s LLVM is doing the right thing and using less registers!
So the correct code is this:
void a() {
int a = 0;
int b = 0;
__asm__("\n"
"\tmov %0, 0\n"
"\tldr %0, %1\n"
"\tmov %1, 0\n"
: "=&r"(a), "+m"(b)
);
}
Which results in the following assembly:
.globl _a
.align 2
.code 16
.thumb_func _a
_a:
sub sp, #8
movs r0, #0
movt r0, #0
str r0, [sp, #4]
str r0, [sp]
mov r0, sp
@ InlineAsm Start
mov r1, 0
ldr r1, [r0]
mov [r0], 0
@ InlineAsm End
str r1, [sp, #4]
add sp, #8
bx lr
And the following LLVM:
define void @a() nounwind ssp {
%a = alloca i32, align 4
%b = alloca i32, align 4
store i32 0, i32* %a, align 4
store i32 0, i32* %b, align 4
%1 = call i32 asm "\0A\09mov $0, 0\0A\09ldr $0, $1\0A\09mov $1, 0\0A", "=&r,=*m,*m"(i32* %b, i32* %b) nounwind, !srcloc !0
store i32 %1, i32* %a, align 4
ret void
}
Assembly – beware local label names with “-dead_strip” option!
March 28th, 2011I came across a very strange bug whilst developing an iOS application whereby the application would seg fault and whilst stepping through the code I found it was going all over the place. This lead me to run the application through otool, and I discovered that half the code for a function was missing!
Here is an example of what happened…
Consider the following C file. It’s just a very simple function that has some inline assembly (to count down from 10 to 0) and a very simple function that does absolutely nothing.
void func() {
int tmp;
__asm__ __volatile__ (
"\tmov %0, #10\n"
".loop:\n"
"\tsubs %0, %0, #1\n"
"\tbne .loop\n"
: "=r" (tmp)
: "r" (tmp)
);
}
void funcB() {
}
Let’s see what happens when we compile it for iOS…
.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 _func
_func:
@ args = 0, pretend = 0, frame = 4
@ frame_needed = 1, uses_anonymous_args = 0
stmfd sp!, {r7, lr}
add r7, sp, #0
sub sp, sp, #4
ldr r3, [sp]
mov r3, #10
.loop:
subs r3, r3, #1
bne .loop
str r3, [sp]
sub sp, r7, #0
ldmfd sp!, {r7, pc}
.align 2
.globl _funcB
_funcB:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 1, uses_anonymous_args = 0
stmfd sp!, {r7, lr}
add r7, sp, #0
ldmfd sp!, {r7, pc}
.subsections_via_symbols
That all looks fairly normal and we could quite happily believe that was going to work just fine. So, let’s use this function in a test application. The code below is just a very simple application that calls the ‘func()’ function and then returns.
void func();
int main() {
func();
return 0;
}
So now let’s see what happens when we link this with the same options that you would have on by default in an iOS application (hint: -dead_strip is active).
Output from ‘otool -vV -t’ on the linked application:
_main:
00002fa0 e92d4080 push {r7, lr}
00002fa4 e28d7000 add r7, sp, #0 @ 0x0
00002fa8 eb000002 bl _func
00002fac e3a03000 mov r3, #0 @ 0x0
00002fb0 e1a00003 mov r0, r3
00002fb4 e8bd8080 pop {r7, pc}
_func:
00002fb8 e92d4080 push {r7, lr}
00002fbc e28d7000 add r7, sp, #0 @ 0x0
00002fc0 e24dd004 sub sp, sp, #4 @ 0x4
00002fc4 e59d3000 ldr r3, [sp]
00002fc8 e3a0300a mov r3, #10 @ 0xa
What?! Where’s the rest of the ‘func()’ code?! Not only is it missing, but it would appear that ‘func()’ just simply stops without ever returning?! That looks very suspicious… So, let’s compile it without the ‘-dead_strip’ option:
Output from ‘otool -vV -t’ on the linked application:
_main:
00002f80 e92d4080 push {r7, lr}
00002f84 e28d7000 add r7, sp, #0 @ 0x0
00002f88 eb000002 bl _func
00002f8c e3a03000 mov r3, #0 @ 0x0
00002f90 e1a00003 mov r0, r3
00002f94 e8bd8080 pop {r7, pc}
_func:
00002f98 e92d4080 push {r7, lr}
00002f9c e28d7000 add r7, sp, #0 @ 0x0
00002fa0 e24dd004 sub sp, sp, #4 @ 0x4
00002fa4 e59d3000 ldr r3, [sp]
00002fa8 e3a0300a mov r3, #10 @ 0xa
.loop:
00002fac e2533001 subs r3, r3, #1 @ 0x1
00002fb0 1afffffd bne .loop
00002fb4 e58d3000 str r3, [sp]
00002fb8 e247d000 sub sp, r7, #0 @ 0x0
00002fbc e8bd8080 pop {r7, pc}
_funcB:
00002fc0 e92d4080 push {r7, lr}
00002fc4 e28d7000 add r7, sp, #0 @ 0x0
00002fc8 e8bd8080 pop {r7, pc}
Ah, that’s better! The loop is back and so is the return. Also, ‘funcB()’ is still in there. So, what has happened you may ask. Well, -dead_strip is designed to remove symbols from a binary that are not required. So we’d expect ‘funcB’ to be removed, but not .loop as it’s part of ‘func’. However, if we look closer, what has happened is that ‘.loop’ has become a top level symbol rather than a symbol local to the ‘func’ symbol. So -dead_strip assumed that it was a symbol not used anywhere (as it’s only accessed from within .loop itself) and so it removed it, resulting in a completely mangled application binary.
To stop this happening you must always prefix your local symbols with ‘L’ (as per the GCC documentation!). But I think this is an excellent example of what can go wrong if you just do 1 tiny thing wrong with inline assembly.
As a side note, I decided to try compiling/assembling/linking all of the above for Android as well. Interestingly the results were different. First I’ll show the outputs of the various stages and then explain the results.
The assembly generated for Android:
.arch armv6
.fpu softvfp
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 6
.eabi_attribute 18, 4
.file "test.c"
.text
.align 2
.global func
.type func, %function
func:
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 1, uses_anonymous_args = 0
@ link register save eliminated.
str fp, [sp, #-4]!
add fp, sp, #0
sub sp, sp, #12
ldr r3, [fp, #-8]
#APP
@ 3 "test.c" 1
mov r3, #10
.loop:
subs r3, r3, #1
bne .loop
@ 0 "" 2
str r3, [fp, #-8]
add sp, fp, #0
ldmfd sp!, {fp}
bx lr
.size func, .-func
.align 2
.global funcB
.type funcB, %function
funcB:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 1, uses_anonymous_args = 0
@ link register save eliminated.
str fp, [sp, #-4]!
add fp, sp, #0
add sp, fp, #0
ldmfd sp!, {fp}
bx lr
.size funcB, .-funcB
.ident "GCC: (GNU) 4.4.3"
.section .note.GNU-stack,"",%progbits
Disassembly of linked app for Android (without stripping):
000082e0 <main>:
82e0: e92d4800 push {fp, lr}
82e4: e28db004 add fp, sp, #4 ; 0x4
82e8: eb000002 bl 82f8 <func>
82ec: e3a03000 mov r3, #0 ; 0x0
82f0: e1a00003 mov r0, r3
82f4: e8bd8800 pop {fp, pc}
000082f8 <func>:
82f8: e52db004 push {fp} ; (str fp, [sp, #-4]!)
82fc: e28db000 add fp, sp, #0 ; 0x0
8300: e24dd00c sub sp, sp, #12 ; 0xc
8304: e51b3008 ldr r3, [fp, #-8]
8308: e3a0300a mov r3, #10 ; 0xa
0000830c <.loop>:
830c: e2533001 subs r3, r3, #1 ; 0x1
8310: 1afffffd bne 830c <.loop>
8314: e50b3008 str r3, [fp, #-8]
8318: e28bd000 add sp, fp, #0 ; 0x0
831c: e8bd0800 pop {fp}
8320: e12fff1e bx lr
00008324 <funcB>:
8324: e52db004 push {fp} ; (str fp, [sp, #-4]!)
8328: e28db000 add fp, sp, #0 ; 0x0
832c: e28bd000 add sp, fp, #0 ; 0x0
8330: e8bd0800 pop {fp}
8334: e12fff1e bx lr
Disassembly of linked app for Android (after using strip command):
000082e0 <main>:
82e0: e92d4800 push {fp, lr}
82e4: e28db004 add fp, sp, #4 ; 0x4
82e8: eb000002 bl 82f8 <func>
82ec: e3a03000 mov r3, #0 ; 0x0
82f0: e1a00003 mov r0, r3
82f4: e8bd8800 pop {fp, pc}
000082f8 <func>:
82f8: e52db004 push {fp} ; (str fp, [sp, #-4]!)
82fc: e28db000 add fp, sp, #0 ; 0x0
8300: e24dd00c sub sp, sp, #12 ; 0xc
8304: e51b3008 ldr r3, [fp, #-8]
8308: e3a0300a mov r3, #10 ; 0xa
830c: e2533001 subs r3, r3, #1 ; 0x1
8310: 1afffffd bne 830c <func+0x14>
8314: e50b3008 str r3, [fp, #-8]
8318: e28bd000 add sp, fp, #0 ; 0x0
831c: e8bd0800 pop {fp}
8320: e12fff1e bx lr
You can see that the Android GCC has done a much better job at stripping out the symbols. This is because of a subtle “.size” attribute given to functions in the assembly for Linux (and therefore Android) which tells the assembler how big the function is. However, this doesn’t exist on Mac and the size is calculated by taking the distance between the start of a symbol and the next symbol.
This actually helps us to understand a bit more what actually went wrong. If you look back up at the assembly generated for iOS and Android you’ll see that the ‘.loop’ appears as a top level symbol, which is confirmed by running ‘nm’ on the resulting object file. This sounds all wrong, since the .loop symbol should really be local to the ‘func()’ function. The reason being because you need to prefix local symbols with ‘L’. If we change ‘.loop’ for ‘Lloop’ in the sample file, then these are the resulting outputs showing the iOS linker doing the right thing this time even with -dead_strip enabled.
Compiled output:
.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 _func
_func:
@ args = 0, pretend = 0, frame = 4
@ frame_needed = 1, uses_anonymous_args = 0
stmfd sp!, {r7, lr}
add r7, sp, #0
sub sp, sp, #4
ldr r3, [sp]
mov r3, #10
Lloop:
subs r3, r3, #1
bne Lloop
str r3, [sp]
sub sp, r7, #0
ldmfd sp!, {r7, pc}
.align 2
.globl _funcB
_funcB:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 1, uses_anonymous_args = 0
stmfd sp!, {r7, lr}
add r7, sp, #0
ldmfd sp!, {r7, pc}
.subsections_via_symbols
Disassembly of linked application:
_main:
00002f8c e92d4080 push {r7, lr}
00002f90 e28d7000 add r7, sp, #0 @ 0x0
00002f94 eb000002 bl _func
00002f98 e3a03000 mov r3, #0 @ 0x0
00002f9c e1a00003 mov r0, r3
00002fa0 e8bd8080 pop {r7, pc}
_func:
00002fa4 e92d4080 push {r7, lr}
00002fa8 e28d7000 add r7, sp, #0 @ 0x0
00002fac e24dd004 sub sp, sp, #4 @ 0x4
00002fb0 e59d3000 ldr r3, [sp]
00002fb4 e3a0300a mov r3, #10 @ 0xa
00002fb8 e2533001 subs r3, r3, #1 @ 0x1
00002fbc 1afffffd bne 0x2fb8
00002fc0 e58d3000 str r3, [sp]
00002fc4 e247d000 sub sp, r7, #0 @ 0x0
00002fc8 e8bd8080 pop {r7, pc}
This all serves to illustrate the point that it’s worth knowing about the options of your compiler, assembler & linker and understanding how everything fits together.
Blocks in C++ classes – very broken
November 4th, 2010I was trying to use blocks (an Apple extension to the C language) in a C++ class when I came across a very strange problem. If you try to declare a block inside a C++ class member function that declares variables inside the block, then you end up with GCC (the one that comes with the Mac/iOS SDK) throwing an error.
For instance, consider this code:
class SomeClass {
public:
SomeClass() {}
~SomeClass() {}
void doSomething() {
void (^block)(void) = ^{
int a = 0;
};
}
};
int main (int argc, char * const argv[]) {
return 0;
}
If you compile it, GCC will throw this error:
main.cpp: In function 'void __doSomething_block_invoke_1(void*)': main.cpp:8: error: 'int SomeClass::a' is not a static member of 'class SomeClass'
Sadly there is no workaround that I can find as yet.
I have found a (not very nice) workaround:
class SomeClass {
public:
SomeClass() {}
~SomeClass() {}
void doSomething() {
void (^block)(void) = ^{
int ::a;
a = 0;
};
}
};
int main (int argc, char * const argv[]) {
return 0;
}
Note that you cannot initialise the variable at the same time as declaring it inside the block. You must declare it, forcing global scope and then initialise it.
ARM Hacking: EXC_ARM_DA_ALIGN exception
October 6th, 2010I came across a problem today that I’d seen before but couldn’t remember when. Then I stumbled across Peter Bakhirev writing up his findings at Byte Club about a problem I’d helped him with. So I thought I’d quickly write up my summary here incase it helps anyone else.
It started back when I was browsing the Apple developer forums once – I came across someone having a problem where the EXC_ARM_DA_ALIGN exception was thrown. It turned out that this was a problem with setting the value of a variable by dereferencing a pointer, like so:
char *mem = malloc(16); // alloc 16 bytes of data double *dbl = mem + 2; double set = 10.0; *dbl = set;
The compiler was emitting a STMIA instruction that was using a memory location that isn’t word (32-bit) aligned (because of the +2 into the ‘mem’ memory location – assuming mem is word aligned). This causes the processor to throw the exception that bubbles up as an EXC_ARM_DA_ALIGN.
The solution above would be to memcpy instead of dereferencing like so:
char *mem = malloc(16); // alloc 16 bytes of data double *dbl = mem + 2; double set = 10.0; memcpy(dbl, &set, sizeof(set));
This is just a simple example of the problems that can occur when you’re not careful with reading/writing arbitrary memory that you have allocated. Granted, it’s probably a compiler bug in this case, but it illustrates the point.
Compiling Boost 1.44 for iPhone
September 27th, 2010As a follow up to my other post about compiling Boost for iOS, here is how to do it for 1.44.
First, edit your user-config.jam (i.e. edit ~/user-config.jam) to include the following:
using darwin : 4.2.1~iphone : /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.2 -arch armv7 -mthumb -fvisibility=hidden -fvisibility-inlines-hidden : <striper> : <architecture>arm <target-os>iphone ; using darwin : 4.2.1~iphonesim : /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc-4.2 -arch i386 -fvisibility=hidden -fvisibility-inlines-hidden : <striper> : <architecture>x86 <target-os>iphone ;
Then, follow these steps to install:
# <grab source from boost.org>
tar xzf boost_1_44_0.tar.gz
cd boost_1_44_0
./bootstrap.sh
# Set this to whatever you want to build against
SDK_VERSION="4.1"
# Install for device:
./bjam --prefix=${HOME}/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS${SDK_VERSION}.sdk/usr toolset=darwin architecture=arm target-os=iphone macosx-version=iphone-${SDK_VERSION} define=_LITTLE_ENDIAN link=static install
# Install for simulator
./bjam --prefix=${HOME}/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator${SDK_VERSION}.sdk/usr toolset=darwin architecture=x86 target-os=iphone macosx-version=iphonesim-${SDK_VERSION} link=static install
[This will install boost into a prefix directory of ${HOME}/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator${SDK_VERSION}.sdk/usr]
iPhone Programming: The Big Nerd Ranch Guide
May 12th, 2010I got into Mac OS X / Cocoa / iPhone programming after reading the wonderful book by Aaron Hillegass called Cocoa Programming for Mac OS X and always thought that Big Nerd Ranch should do an iPhone book and, they have. I’ve had a flick through it and it looks like an excellent read. It’s called iPhone Programming: The Big Nerd Ranch Guide. On the outset it looks to be a similar style to Cocoa Progamming for Mac OS X in that it talks about Objective-C and things you need to know there such as memory management and then goes on to describe the various parts of the iPhone SDK.
Anyway, I’d recommend buying it if you’re thinking about getting into iPhone programming.
