Swift ASM at a glance
giving a function like:
fileprivate func createAndLoadInterstitial() {
interstitial = GADInterstitial(adUnitID: "ca-app-pub-3940256099942544/4411468910")
}
What does it looks like in ASM? (ignoring those name mangling)
__text:0000000100008008 SUB SP, SP, #0xA0
__text:000000010000800C STP X29, X30, [SP,#0x90]
__text:0000000100008010 ADD X29, SP, #0x90
__text:0000000100008014 STUR X0, [X29,#self]
__text:0000000100008018 STUR X0, [X29,#-0x18]
__text:000000010000801C BL __TMaCSo15GADInterstitial ; type metadata accessor for __ObjC.GADInterstitial
__text:0000000100008020 ADRP X30, #aCaAppPub394025@PAGE ; "ca-app-pub-3940256099942544/4411468910"
__text:0000000100008024 ADD X30, X30, #aCaAppPub394025@PAGEOFF ; "ca-app-pub-3940256099942544/4411468910"
__text:0000000100008028 MOV W8, #0x26
__text:000000010000802C MOV X1, X8
__text:0000000100008030 MOV W2, #1
__text:0000000100008034 STUR X0, [X29,#-0x20]
__text:0000000100008038 MOV X0, X30
__text:000000010000803C BL __TFSSCfT21_builtinStringLiteralBp17utf8CodeUnitCountBw7isASCIIBi1__SS ; String.init(_builtinStringLiteral:Builtin.RawPointer,utf8CodeUnitCount:Builtin.Word,isASCII:Builtin.Int1)
__text:0000000100008040 LDUR X3, [X29,#-0x20]
__text:0000000100008044 BL __TFCSo15GADInterstitialCfT8adUnitIDSS_S_ ; __ObjC.GADInterstitial.__allocating_init(adUnitID:String)
Notice it first puts "ca-app-pub-3940256099942544/4411468910"
into x30
and later put into x0
and then it call BL BL __TFSSCfT21_builtinStringLiteralBp17utf8CodeUnitCountBw7isASCIIBi1__SS
inside __TFSSCfT21_builtinStringLiteralBp17utf8CodeUnitCountBw7isASCIIBi1__SS
:
__stubs:00000001001435D4 ; =============== S U B R O U T I N E =======================================
__stubs:00000001001435D4
__stubs:00000001001435D4
__stubs:00000001001435D4 ; String.init(_builtinStringLiteral : Builtin.RawPointer, utf8CodeUnitCount : Builtin.Word, isASCII : Builtin.Int1) -> String
__stubs:00000001001435D4 __TFSSCfT21_builtinStringLiteralBp17utf8CodeUnitCountBw7isASCIIBi1__SS
__stubs:00000001001435D4 ; CODE XREF: InterstitialExample.ViewController.createAndLoadInterstitial()+34↑p
__stubs:00000001001435D4 ; InterstitialExample.ViewController.createAndLoadInterstitial()+E4↑p ...
__stubs:00000001001435D4 NOP
__stubs:00000001001435D8 LDR X16, =__imp___TFSSCfT21_builtinStringLiteralBp17utf8CodeUnitCountBw7isASCIIBi1__SS
__stubs:00000001001435DC BR X16 ; __imp___TFSSCfT21_builtinStringLiteralBp17utf8CodeUnitCountBw7isASCIIBi1__SS
__stubs:00000001001435DC ; End of function String.init(_builtinStringLiteral:Builtin.RawPointer,utf8CodeUnitCount:Builtin.Word,isASCII:Builtin.Int1)
We see it does not use `x0`. Now we continue to check `BL __TFCSo15GADInterstitialCfT8adUnitIDSS_S_`:
__text:0000000100008274 ; GoogleMobileAds::GADInterstitial __cdecl __ObjC.GADInterstitial.__allocating_init(adUnitID:String)->__ObjC.GADInterstitial()
__text:0000000100008274 __TFCSo15GADInterstitialCfT8adUnitIDSS_S_
__text:0000000100008274 ; CODE XREF: InterstitialExample.ViewController.createAndLoadInterstitial()+3C↑p
__text:0000000100008274
__text:0000000100008274 var_30 = -0x30
__text:0000000100008274 var_28 = -0x28
__text:0000000100008274 var_20 = -0x20
__text:0000000100008274 var_18 = -0x18
__text:0000000100008274 var_10 = -0x10
__text:0000000100008274 var_8 = -8
__text:0000000100008274 var_s0 = 0
__text:0000000100008274
__text:0000000100008274 SUB SP, SP, #0x40
__text:0000000100008278 STP X29, X30, [SP,#0x30+var_s0]
__text:000000010000827C ADD X29, SP, #0x30
__text:0000000100008280 LDR X8, [X3]
__text:0000000100008284 CMP X8, #0xE
__text:0000000100008288 MOV X8, X3
__text:000000010000828C STUR X2, [X29,#var_8]
__text:0000000100008290 STUR X1, [X29,#var_10]
__text:0000000100008294 STR X0, [SP,#0x30+var_18]
__text:0000000100008298 STR X3, [SP,#0x30+var_20]
__text:000000010000829C STR X8, [SP,#0x30+var_28]
__text:00000001000082A0 B.NE loc_1000082B0
__text:00000001000082A4 LDR X8, [SP,#0x30+var_20]
__text:00000001000082A8 LDR X9, [X8,#8]
__text:00000001000082AC STR X9, [SP,#0x30+var_28]
__text:00000001000082B0
__text:00000001000082B0 loc_1000082B0 ; CODE XREF: __ObjC.GADInterstitial.__allocating_init(adUnitID:String)+2C↑j
__text:00000001000082B0 LDR X0, [SP,#0x30+var_28]
__text:00000001000082B4 BL _objc_allocWithZone
__text:00000001000082B8 LDR X30, [SP,#0x30+var_18]
__text:00000001000082BC STR X0, [SP,#0x30+var_30]
__text:00000001000082C0 MOV X0, X30
__text:00000001000082C4 LDUR X1, [X29,#var_10]
__text:00000001000082C8 LDUR X2, [X29,#var_8]
__text:00000001000082CC LDR X3, [SP,#0x30+var_30]
__text:00000001000082D0 BL __TTOFCSo15GADInterstitialcfT8adUnitIDSS_S_ ; __ObjC.GADInterstitial.init(adUnitID:String)
__text:00000001000082D4 LDP X29, X30, [SP,#0x30+var_s0]
__text:00000001000082D8 ADD SP, SP, #0x40
__text:00000001000082DC RET
__text:00000001000082DC ; End of function __ObjC.GADInterstitial.__allocating_init(adUnitID:String)
First, we saw it store `x0` into `[SP, #0x18]` ( `STR X0, [SP,#0x18]`)
and later use `x30` to put back to `x0` again:
__text:00000001000082B8 LDR X30, [SP,#0x18]
__text:00000001000082BC STR X0, [SP,#0x30+var_30]
__text:00000001000082C0 MOV X0, X30
and then another BL: `BL __TTOFCSo15GADInterstitialcfT8adUnitIDSS_S_`
inside `__TTOFCSo15GADInterstitialcfT8adUnitIDSS_S_`, which is the true function `__ObjC.GADInterstitial.init(adUnitID:String)`:
__text:000000010000ACB8 SUB SP, SP, #0x30
__text:000000010000ACBC STP X29, X30, [SP,#0x20]
__text:000000010000ACC0 ADD X29, SP, #0x20
__text:000000010000ACC4 STUR X2, [X29,#var_8]
__text:000000010000ACC8 STR X3, [SP,#0x20+var_10]
__text:000000010000ACCC BL __TFE10FoundationSS19_bridgeToObjectiveCfT_CSo8NSString ; String._bridgeToObjectiveC()
__text:000000010000ACD0 ADRP X1, #selRef_initWithAdUnitID_@PAGE
__text:000000010000ACD4 ADD X1, X1, #selRef_initWithAdUnitID_@PAGEOFF
__text:000000010000ACD8 LDR X1, [X1] ; "initWithAdUnitID:"
__text:000000010000ACDC MOV X2, X0
__text:000000010000ACE0 LDR X3, [SP,#0x20+var_10]
__text:000000010000ACE4 STR X0, [SP,#0x20+var_18]
__text:000000010000ACE8 MOV X0, X3 ; void *
__text:000000010000ACEC BL _objc_msgSend
We will see it eventually calls initWithAdUnitID:
, whose parameter is on x2
, which is exactly previous x0
.
A very simple swift function goes so long to finally get initialized, which is very different from ObjC.
ObjC counterpart
First we write the same way:
- (void)createAndLoadInterstitial {
self.interstitial =
[[GADInterstitial alloc] initWithAdUnitID:@"ca-app-pub-3940256099942544/4411468910"];
}
Inside its ASM code, stripping off irrelevant code:
__text:00000001000082E4 ADRP X8, #0x100186000
__text:00000001000082E8 ADD X8, X8, #0xD78 // addr of "ca-app-pub-3940256099942544/4411468910"
__text:00000001000082EC ADRP X9, #0x1001CA000
__text:00000001000082F0 ADD X9, X9, #0xAC8 // addr of initWithAdUnitID:
__text:00000001000082F4 LDR X1, [X9] ; "initWithAdUnitID:"
__text:00000001000082F8 MOV X2, X8
__text:00000001000082FC BL _objc_msgSend ; -[GADInterstitial initWithAdUnitID:]
This is the ObjC output, quite straightforward, right? Why swift makes so different?