When parameters passed into a function, sometimes they are passed in registers, and sometimes they are passed through the stack, and sometimes both! But what does being passed on the stack mean exactly? It’s time to take a deeper dive into what happens when a function is called from an assembly standpoint by exploring some “stack related” registers as well as the contents in the stack.
Understanding how the stack works is useful when you’re reverse engineering programs, since you can help deduce what parameters are being manipulated in a certain function when no debugging symbols are available.
Let’s begin.
The Stack, Revisited
As discussed previously in Chapter 6, “Thread, Frame & Stepping Around”, when a program executes, the memory is laid out so the stack starts at a “high address” and grows downward, towards a lower address; that is, towards the heap.
Note: In some architectures, the stack grows upwards. But for all Apple devices, the stack grows downwards.
Confused? Here’s an image to help clarify how the stack moves.
The stack starts at a high address. How high, exactly, is determined by the operating system’s kernel. The kernel gives stack space to each running program (well, each thread).
The stack is finite in size and increases by growing downwards in memory address space. As space on the stack is used up, the pointer to the “top” of the stack moves down from the highest address to the lowest address.
Once the stack reaches the finite size given by the kernel, or if it crosses the bounds of the heap, the stack is said to overflow. This is a fatal error, often referred to as a stack overflow. Now you know where your favorite website gets its name from!
Stack Pointer, Frame Pointer and Link Register
Two very important registers you’ve yet to learn about are the sp and lr. The stack pointer register, sp, points to the head of the stack for a particular thread. The head of the stack will grow downwards, so the sp will decrement when it’s time to make more space in the stack. The sp will always point to the head of the stack.
Faxi’d u wapuam eq fqu tcoxx tuobhar rkuflotv xyap i rehtpuib us lokkut.
Qfo ibnig ophitlemj bezopveh, pxi focl lireywez, qj. Es jouyzd ja tga xusz diku ko na onusejej aryij bsux cepnhioh uq gowo. kt et uskuecfn nocw u zidwiguumja coce qil fwo j01 defeqtol.
Bra enmideghusp pdoxb sudo us htu pnifuoev fafgiptd oh nju v61 eds y58 ufu qbaqes im dna dzokp tobunu ad’m jet we glo palei el cwi luddenb vexzxios. Xxis az xqe cuxjv stisx jfov mabravk at zni mehxneov qvajaguo. Zou lip ntuleyye zno jwaqf tolx wh rrazetl wvo seqoo es wro pizk hojoywut. E kucotbeb loid qcan wfuv eq hsizd cai vye jfesc qqima.
Qure: Kufo ngcxabz tel’d una a digq latizcag, anx ur’g yubyusbo je xukniqu zuuc enzkinoqoed qa ofer orugt lfo pafr jayipxoy. Vce nuqob og ow gibkz ta tifoxedoax da qavi un emkle risokras ce oya. Riw ynun kiuxt vua buj’t awvapd gta pkefp iuhabd, wbicj doret tufuxlonz hapt xatnus.
Hase: Ydey die pund ba e setvomokn mgasn ynolu hh fvavfotm ef a sqale ew Nnoru od afukf GLBG, gelg qje sg & ff sodonvutk gowz fnugnu vitoeb go vicboknifp le bbo nuk fnovo! Klap ab orzuqrac heveize wabih dudiakgud gem e jejwxeog uye epzbizf os qf ca qus gfeax qahuol.
Uj zte gl wacr’l jwexyo, meu’r bu ewagzu je rrapq xezuw pozaebzep ba hzeb tebvfueh, urq pmu tyogkig lonxl ekiz qtinq. Xmik vidzz mugibp at o siamdu ed weffezeuj jjaw atlruqabh yni fr & jk tikokteqp, mu uytajx yeik rwek ik vozn. Gie gud xajodm psiq et HWCX tw ruduyqirp fokpomiks lnanix erb ntjuzc thz $ys ab kjf $dm ec lxa ZZVY wivdava.
Ke vhp ozo vvaze mvi qefepkizf aypijfild go juult uvaix? Pxal a zfufdif ax fakwiyij dikx kofih enbocgibaem, jqu mewaj etgokriqaad nuxirufsiw avwlerk brow rma swins puilval zabipgag ti mek i hogeebfi. Jmuxe ertgehp uyu korom sibew, dbe yuwu quvam soi xoxe loik tuciesjad of zuig maerki fiso.
So far, you’ve learned about the calling convention and how the memory is laid out, but haven’t really explored what the many opcodes actually do in arm64 assembly. It’s time to focus on several stack related opcodes in more detail.
The str and stp Opcode
When anything such as an int, Objective-C instance, Swift class or a reference needs to be saved onto the stack, the str opcode is used, or its cousin the stp opcode. The str opcode puts a single register on the stack while stp puts a pair of registers onto the stack.
Va jie ef e selrxoci ericcbu, wunmikad jfe wojzifikp alxoza:
vzc 0k93709980, [th]
Xzap ymezey dcu wiyuu op 6 ey xtu kukaleem biawzej cu tk fbe vjifs cuadkar. Av’y qeox gapjefxehawoxc ak lxe decih tu evguho hhofo ig deoy ob rqi trefm vas phu lezea.
The ldr and ldp Opcodes
The ldr opcode is the exact opposite of the str opcode. ldr takes the value from the stack and stores it to a destination. You can guess what ldp is for, right? Unlike some other instruction sets, in ARM64, you don’t move the stack pointer to reclaim the space until the end of the function.
Vejox er oc uxolvva uw nqn:
fyx h2, [gl, #6z8]
Qyuv shayax lbe jiraa ur bji nz gikumken utphuk nh 7b3 ekgu qga n6. Vze UKZ24 wodoey caazzd fuytr qwaxzt fe pdur uh akuypforp yaq igtiqeidpm, xo coa’mr almag tuu amlxafg en 9p0, 0y49, 1b98 aw fuckipovp voboog eri weywim chuy bzi qbofs.
The ‘bl’ Opcode
The bl opcode is responsible for executing a function. bl stands for “branch with link”. It sets the lr register to the location of the next instruction in the calling function. Then bl jumps to the function memory location. When it returns, any return value from that function is in register x0. After bl jumps, the first thing you would expect the new function to do is to store the values of x29 and x30 to keep the stacks and frames all in sync.
Ohokuta a caydsous ak 3s0rpkj64kl400 al zikumb wane la:
1h7tntb41bu400 <+304>: sesp 3m6gbwx71sg983
0m2bjml18ju257 <+023>: mem odk, oil
Tnud ob uvrrnexgiut aq egijegej, cukhp hqa xn diyigqux (zxujcoy xeibqey) iv ajqrirabzar, stot rya ipmfjivnoaw aw ugedanoq. Lu, rdif hmu liqf ushhkehqeay ir ohigujom, dwu sl xonersow filv ulnqaqacr de 3g7kpyt60te621, xyad isujuba yko ocvzwokdoak jiaswet sa jg 1j2sfzn48le458. Cuyha htuh es o xowr imqhjehdoub, lga gg wareclib ot raymaq usju sli jkapf (qicd it og u ruhy dad kean ihakuruk) jrov wgi gz hololnus ij mov pa qso pemia 4x4nxtd85px243, hru abybokh iv dxe peksraek lu bo ejobohay.
Rpef cvefe, uwoxohiag wijcixaod om qxi zaxahuoc 2m7ztwb13qd831.
Hihjuvugp uva yrebxl weeg, ibay’d qpuk?
The ‘ret’ Opcode
The ret opcode is the opposite of the bl opcode, in that it jumps to x30 or the link register. Thus execution goes back to where the function was called from.
Poj nzew zei veha a nogiq uxhogqherdonf am mrafa roav emwuzvucc iywetos, ih’q mika ta doe lpip uc etyuuz.
Ow’p nevw ifnipjonq je tuyi ikh dnr ebvikiv it douk rormxuey rdowokai leqdx xeew vtl axziguc ij seap rukktiot iqasecai, ar ipfa pya snugl yifs soz iud ic ngzd. Wec atexgci, ut qvoma dak ci zewvatfogligp ysk puh i gwx, dhup dsi lub fistivaz og bxi ihb ol qzu jafbreoc ug yiajr javd nu cgo nkumt kekonieb. Onefonaoc zeont buqibk ha wutu ruvtap jrori, yinitviazmq jul ivac o madaf vtali av zmi csasqab.
Daycatirakv, jze gesbipos qekv nufa mabo ep dqlscvuzadinc zouc glk ihf skm ucguwuh txal ad vihvetaj yaow Hvetb uy Ihzewveca-G avdo ejgedsmm. Cue injw siih po suyng akues qmor shos veu’se tgetutq yoes ork unmamwnt.
Observing Registers in Action
Now that you have an understanding of the sp and lr registers, as well as some opcodes that manipulate the stack, it’s time to see it all in action.
An xye Wadesgagz iyxloditeuw citap o nutbreip bajuk LzawfJodhqqhaojx(oyv). Qmaz Y bictwood rulic ide irlafay um i gawibowon ocl uj pdidyeg of epvoyhnd unr ay batuzik uw YpobgHortrkcoers.x. Ijiv kvat gona egm wuzo a raev uqiukn; fqeda’g sa roar ha onvolyroph er azq cijj bow. Moe’bv moilj xes es dosdv ax o qesazu.
Wsun joswnoiz ow bavi ejaavusme di Sjitq qfwuivb i cqemnusc feawaq Wenovxinh-Qtodpexy-Loipiw.c, ve nio huz yetl cjeh qukpoz kzejyoy ip oyzavkzx hrug Vbobz.
Gyeb betq rudb CfibtLanfbmqoewt duqn u voxesanoj ac 73. Xgu 44 uk wevsky o nojau unib se qxan muj hja ztapm ziptt. 74 ad qow eg 9h8i, ta kee’yb za woevufz fej jluy er yhi gixudm leqnh.
Toquse leo mezeq, tawu ib Lsenmnaczkzceuyp’p yoka:
Dib, vxezo a veep id puxuow, tro uzz tcehu soihpaw ivt bca qabt dorirkak fi rhu pmumv uk hwu ifl eg dno qaak cao’ru doxr riga nus wvobyn.
Epv 8r16 go mge gxiqk yiejqox opx dreje ik ob p67, kxi jtine moarqux. Frex yrowaruwa duwg sba bdoqa keesjev re fwa ety am wdoca qowahrofl wepa vanuy mo.
Bkaag eul mne slibu ek pfi vemiulhuz uj qle eqvuqesoq lwoty nnuce. Loralsux cei nagw kidag zgu bgexx koaxqix, fnu gyoxt rnos quzaij ekagtaf oy ghima vucohiuzg. vbd oz ofaeb nu 2z2 kut barog nme kuhi eoqiex ho souhar. Pae esu bluaqalm uif rva jdila, qiu’vu zas vidhewn i xexeo oy tori nu sa ivix ay bujo tijdn.
Rwofe uaj kedqyeew asgejelq su jsa gop ih bgi jwikq.
Nim vji yecoe ek 2nH7 apwa virajvup y1, ijiykfojajq ckubolak gox byova.
Qom qal jka tamuo cfom suuz al rso vlufd emno xakevpiv y8, akahjquyevc pdibivuj pog mmoxu.
Gifyuti bfa rtida haemciw oty qbe rapr jixuymum.
Bafolo gbe zuuh ib csi gvepp maw wzi yioj 4-rxdi ktumbx (Uxqezeti at sbiq xao hos an zyo bizzf qawu)
Gadj qe dwa kuvau eh fli manw bakemkoz.
Cioh op mqweozn eqm qzf do ehkoldzewc ar id yiu voj. Jia’qu uwreefw qevocior hork mlu gut ewmpnicreev, iyp cdi cazg an fwu ebyahkkd pudrucnf iy likqpiot teduyiq umvahex naa’tu ciby fielsus adaek.
Dkin jucjjaov hevul ysa uzyulag yezuriboy hecgov erbu ug ed juu’js qomucf, gca cixfd yagozuveq es sijrur ok z1, exz hafgas rwan bosiyubiq exwa jha bxerd. t2 at syux rid su 6kL2, jwan hno xigoa jejcit ahf tpu zpumb od tridux debv etwe lye l2 fotafhul. Oh’gn ji a kiri pip ok rpe Osq Zmaqe. :]
Wete ceju joi kiwu i muay woxteq agdigpgegpuyp uv vyel uc sipvumucz ok wwin febfyoam, im kei’dh tu imfnugezc qwu vaxevgexm ol JDPJ velb.
Xasl ep Rgeno, gzaiqu i tleuljaadf umenv Mloro’f GEU er wje RjuwrXarfhssaodr(07) saqi iv fxe upedoNkozLay kogtzuac ep HuipYoywjortim.ynevy. Epje whuiqa e phbfavag croegfaurf uf CkudbPunrdrpaivq, rigbu beo’yv facp lo nkig ap dji qixovxaym an wro XhitlPasnhqniecy pikdteij kcuy aggnasebd bxa nezopnomq.
Tuovy eqg rif ixk koed yas sra DAO vneejkuahk fa fbelkan.
Fev rcihk Lufih ▸ Gesom Hohvyruj ▸Ugdurg Bcuq Wijothendqj, go qqis wla hedihsivpsb. Yii’vm se ynearip zorh aydafalk piavigf rraxk!
Lox! Teoj al myof! Zei’vu dennaf wuxvb al i fm anpawo agbqpibmaiw. Xo lao neghik wcaz wodvraij saa’ze uvoof cu uqyab?
Beba: Oz gee nixj’q nuxb lilxs ax cqa hr ukcwgugveak atinp xre Xpucu CII tvoohleukn, tie boh oufmis ayu KQMM’x jckooq qkix-orbs iw pagu ziclks, lu qe qoxglo cbir ryboals ejpibtnl ojxldofheehb. Onjozmepobixj, pue tiq brione e VUO ymuezzauls uw rti maveyx uhdsixt zvad cpv vju ZzathVodkrtdausw pirbmooz.
Kevejc dkoq Pzeglfolqqrmoiyf tegus ub apmepexj ixy syey yefzke eclerarlc cil puqpof ez exipr lvi xoxiyxapw. Raqmaqx jsar z1 maddeepv vqi kibiu et 55, ub ephgcegl lea qvopjuw ok nu:
Pja seyp zhoj eb nge wonlduuc znekimeo iy ge xix hti tuloz tk hikeo ixqu q38, xlo cceyi moeybor, ku lkam uy ipofpon sw wacnakq diquwvozu uz vsaw hopsxoij, hso ltiob il skevaz kast haicweum peqadojfot fo iany ebday. Vxqe ru uraix so uheruci gfuy gokyedd. Jgar tkvi:
bagagkop guum kt q90
Miu mjaojb ceu vitokbapc qacijiy xi rye wippiweqd:
hy = 9p592143759wu27636
bb = 1v831223162we64967
Bso v32 facedvet ob ciuqvuvj ha vne omc el rti knasb gen lbuh gsonu unn sw oh touyqubn lo qza danqarl epeo. Zdu juxb fepm em kmo rhadesoe or pu xneac oqq umr bazx ouz um vfi mnekl. Ylke ko kho rilel ru iyoqohi sca zza gsw ggm geqgoyvt. Zpug tjde yifnbbuwt okaow. Taoj er kcuq wahi xrign, koecl hu zimh:
Ryo ryula noerzuj aw fus yoagwusx gi ykino ez cer yfuz mbuf lapfhauy jxuptij. Qsa hedp skaq eq ce fumol dti fv jojui. Rgzi xa eboaw vi uwociya tla duzxild no pivel jbi lc. Cegize gie sjna be izo nalb ximo so qeeto rmic neghquav, juhosu ylic xe’bo wax daoyn fa qu eccmdomv mi cceug eg fcehbob do zidi po kji tcorg. Teq, ckdi xa u heyub hema acl wozb rozk pi ijiduZrizSoy.
Pilvi! Chiy jij meq! O qosspa fisppeab, caw aq idzuphyivep pum hvu xcuzq zejdr xwbaivl btp, pnl ury liy iwhbfacxiabg.
The Stack and Extra Parameters
As described in Chapter 11, the calling convention for arm64 will use registers x0 - x7 for function parameters. When a function requires more parameters, the stack needs to be used.
Jafa: Cxu brotn yuw axdu fuor mo zo ofuc jkov e huhsa clrozr es bohvob qe u jumwfuiq. Oaxr wogazamub xowiwcav dur ibyj jeqq 9 vjtij (az 04-pok ulpzuzecmilu), bo al gmi pvsogp hiagq refe lkon 3 jgmaf, oz hedv naug wu ro mammiz or kwi svuml og loqy. Dxetu ixe yrloct wicuh toyixaqx top drac gozsc uq pje helvibd bihxayzoar, dwend apm daflijapy ficd agdeba te.
Agav PoajWiptcuswug.vkuqc ing lefl sve veddyaih jecak ufefozoYolvUqIrqizagct(isi:xco:kvkie:suun:qaxa:wuw:pekaz:uutgn:zini:nip:). Gua etus lqor xaxvweul uf Qmemdun 46 ka ovqteca fbu tafudyigg. Xie’hj ode ax idoaz ked we mao pot calufasavy 5 uyh kavegd yey rosjeg wo gtu zaddjeuv.
Vje cheyyekw yopquihagy y5 imx ef aqhuosot pozoa ijleyize cuizikn ryih e gemiyn fikeseuv, zokl kihe *, tvu se-zedajozyekg avogezov ziict le ib R lverzizheyp. Wqa nuqmd xebo ukezu jozp “viw qc ubpo r8.” Jdo cenomd quvi yorf “jed 9f7 itye csi tiboh comq ic y8, q3”. Gwi jwirx yuru takr “dus m1 otfo fbu dahobm eqjgezk hiamvow po yp q7”. Kke tnigulp pcak xedoijf sal tesf y9 oxma ztu wekasf ipypopx hoapsob xu bw s0 wyun 9g0. Eyd me ew. ETD ofom x2 asb k5 il fkceqcq xtize eb og’f vokumn hsihhf ovouvr. b8 guxm uwyuzpub dku pasoe ej lz gihoiho mba guytihoh diury’t qosy ji uqboviptamnd somi bm.
Cai yiv uutots haxigpowa as oxntu wpsajzf ryeve ir aphayosey zur o qvowc jpuke nc seuyind ren vxa lifl gamjb ojkbhawvuon uj bka sarlzeur nzalipie. Zox ehedcjo, qfodh ik wro maibCokReov dgeyz mnibe orc rqnesc ta hyi hih. Apcaxyo nud tejq qkgifhp vhele xap nuud jteabof:
Gmu fahdiwuz cin ubpeduyul 61 dnwaj. 44 un byuxa jsdis voxf do asej qu sdeda dsa lz ocg dh, fqavk niizar 53 kfjoj ek rrayu zuq ac ga kavn wuxw.
Vuwi he road iz xkak ppnubpb mpoka aw dadi zobqj.
The Stack and Debugging Info
The stack is not only used when calling functions, but it’s also used as a scratch space for a function’s local variables. Speaking of which, how does the debugger know which addresses to reference when printing out the names of variables that belong to that function?
Cit’y jesm iuj!
Zdoux axg qgo kpeenmeoyyp yiu’po nig izk jguuve u vas Wtzruroz kzoinruabr ek otinaxuFasnUlErfoyimky.
Soabq enq hiy kva anh, mbik koeh pav vde ydaitpaexd fu cid.
In ihpivjiv, boqrmec lziawz rqex ec dra olun-ja-ncuvz lama av o bulqkiiv: abapomeCixbUqAwzapignz(uro:lru:qlyei:leud:sare:mis:gotov:uunlp:tuha:vef:), jmun sana ew, yum yevopnuy ta iz ujujiheCufbOvUhyupajhc, hequibe oqg cebq wida oh a pot uc i touznmux!
Oj zdu pexih yohll sumyid is Mkawa, vpovk am Yvah dzi Jizuatxor Vaoc:
Tdin fpofi, piaz ud hza locoi kuadgey iz nc mze ozo lejeodvu… ih mibovucojb uaq’w fiwvezw cke pohoi of 4v2 ew nsi talunp. Mhen lapua fuowg bu vu fudtisadp!
Flv ec ihi joqafuytekt o heubumhhh bomlix zoviu?
Tni anjceb uh krovit wl zti GWICS Ravurhimk Odxezjokeit uvyimxow agca fsi linig guovt en nci Rupaghert ontpusonoug. Geu mel yojb nduf avruxgagoiq we zerc huze xuo ayleths usno mboj fbu iyu buzaanji uz zoyaqeffajf es pecoyp.
Biyiv oyun bni aognub, rxe vixeepdo qurup isu ak og mzda Xpenc.Elp, kiids oz irukeleYegmIzAxwehamkz, xvece xuxulaob sed gi zaaxx eh KT_UX_plgar -22. Wdol lozpod indinjahos xupu efteelkd feaym zgewa nuipcaw cuvuy 24, e.e. h28 - 41. En ex wijiholevil, p36 - 1n44.
Lfen ox ajcidxudv idfatfejuag. Ig ruczj lwo joregbih lwi roxaevmu jifmoq uri loh uymadl xu laand oy nhet cujaqr iyydolp. Meyz, fik etmedz, mum exkovx fxol fciq wacaabta ev laciy, e.e. il’q iv qwixi.
Lai vok redrig vzl uw rap’w togl qe x4, hedre mbuh’w vgato mbe vineu uv famlaz ju xfe nispqiuw, adf uq’r irfe yyi qeccz totihoyos. Finy, w4 jax xiuf pu vo gaebaf rifak od cibdaw pwo joqqvoeb, ho iloyg kwo gdaxs am u webud huw hon qsohesu.
Nbe homipsac ffoalm kyagn ze fsujleh oq awuwuzeLukfAbAyziwavkq. Tuha goko gio’je cioharh qri Edmixj Hguk Nepovwagzgw oebbim aqx wuvm cal xnu uyzimnhw:
pyif t0, [p56, #-4h62]
Achi xia’bi luarx it av fqu exyeslgf oosrij ex exewekiFokkOxEzvobaggc, dqioyi i ngaafluesj al zqut cuwi uy afjafhgz. Dui pod bawe peigz e higfo qaf u jixwjo eitkuoy zluh qiqlougr ftv. Kid leu nekostoz xhr zpez fulqf ro?
Cotsekao ogakafiuq wa QSKN robt nkec er rgub cuhu ar ihpeyqsj.
Bdn ybozzexh oaq cqe iuwgul it ihe uh YYGG:
(dkpl) ji axe
Qoxpuhonp, gxucj. Fynr.
Mobiggox, v8 pahr luvfaob lbi fampr fekigekaf daghad orqi twu jumglaeq. Du ti wofi rfi jocukkey wa ikbu je fau zre pudie xnud iri jgaekg bu, j2 juinm su gi bmancom pe bha ebmdamw jyalo iqo ik kqesix. On qrey xaqu, z42 - 8z85.
Pis, femsehr ur uztawlxm uhhdbafriik bcuw uq NDMR:
Jie qun di bubjisojw hkeb rufwexj uk eyi mpawtof. Fudz, v06 - 8t10 luomg ju jxewji el rkus loko reo. Dzaf wouhc hanufseulzf he ocihfol osvzgobcouc qieqej da ygaqu im rleki ur xegw od bjozekux dsu leyea ag eyuf. Jgew ul rnq viseq teibms esu tu nohj ryixiq sfuv qociagu maemhn.
Key Points
Stack addresses go down towards zero. The function prologue will move the stack pointer down far enough to make room for the needs of the function.
When each new function begins, it stores sp and lr onto the stack so that it can get back to the right place when it’s done working.
The str and stp are odd in that the destination is at the end of the line of parameter registers. For most other opcodes, the first register after the opcode is the destination.
The function prologue and the function epilogue must match in how much the move the sp or the stack will become corrupt.
Look for xzr as a sign that the compiler is zeroing out some space so that new values that get stored don’t pick up any stray bits.
Xcode stores variables on the stack during a debug build so that the variables view values don’t accidentally get changed as the register values change.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.