Skip to content

Instantly share code, notes, and snippets.

@gut
Last active September 24, 2015 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gut/956d6431412aad0fc626 to your computer and use it in GitHub Desktop.
Save gut/956d6431412aad0fc626 to your computer and use it in GitHub Desktop.
ppc64 proposal for push/pop operations on assembly level

The handwritten assembly is located where commented and with less indentation levels(lines 40-80).

The idea is to have a reliable push where the stack pointer $r1 remains unchanged.

On this proposal, the $r10 is used as the pointer to the top of the stack and it'll be initialized by having the same address as the stack pointer $r1:

mr 10, 1

Push will be accomplished with 1 instructions:

stdu @push_element_register,  -16(10)

Pop will be accomplished with 2 instructions:

ld  @pop_element_register,  0(10)
addi 10, 10, 16

When branching out of the function (aka when the stack pointer changes), a fake call stack is built in order to save the pushed elements from being overwritten by the new call stack:

mflr 0
std  0, 16(1)     # save LR
stdu 1, -32(10)   # create 32 bytes additionally for the stack and backchain
mr   1, 10
bl @target

When that branch returns, the fake call stack restores the stack pointer $r1 and the pointer to the top of the stack $r10:

addi 10, 1, 32    # restore top of the stack address
ld   1,  0(1)     # backchain
ld   0, 16(1)     # restore LR
mtlr 0
.file "simple.c"
.abiversion 2
.section ".toc","aw"
.section ".text"
.align 2
.globl ret1
.type ret1, @function
ret1:
std 31,-8(1)
stdu 1,-80(1)
mr 31,1
li 9,1
stw 9,32(31)
lwz 9,32(31)
extsw 9,9
std 9,48(31)
lfd 0,48(31)
stfd 0,48(31)
ld 9,48(31)
mr 3,9
addi 1,31,80
ld 31,-8(1)
blr
.long 0
.byte 0,0,0,0,128,1,0,1
.size ret1,.-ret1
.align 2
.globl main
.type main, @function
main:
0: addis 2,12,.TOC.-0b@ha
addi 2,2,.TOC.-0b@l
.localentry main,.-main
mflr 0
std 0,16(1)
std 31,-8(1)
stdu 1,-64(1)
mr 31,1
# initialization for pushing
mr 10, 1 # r10 is the top of the stack address
li 9,0 # element to be pushed
# pushing elements
addi 9, 9, 1
stdu 9, -16(10) # pushing
addi 9, 9, 1
stdu 9, -16(10) # pushing
addi 9, 9, 1
stdu 9, -16(10) # pushing
# build a callstack due to the 'call ret' below
# save r10 so the size is known and update the stack pointer
mflr 0
std 0, 16(1) # save LR
stdu 10,-16(10) # save top of the stack address
stdu 1, -32(10) # create 32 bytes additionally for the stack and backchain
mr 1, 10
bl ret1
# pop the callstack, revert operations
ld 10, 32(1) # restore top of the stack address
ld 1, 0(1) # backchain
ld 0, 16(1)
mtlr 0
# popping elements, r10 restored
ld 9, 0(10) # a pop
addi 10, 10, 16
ld 9, 0(10) # a pop
addi 10, 10, 16
ld 9, 0(10) # a pop
addi 10, 10, 16
mr 9,3
mr 3,9
addi 1,31,64
ld 0,16(1)
mtlr 0
ld 31,-8(1)
blr
.long 0
.byte 0,0,0,1,128,1,0,1
.size main,.-main
.ident "GCC: (Debian 4.9.3-3) 4.9.3"
.section .note.GNU-stack,"",@progbits
@igorsnunes
Copy link

vret and vcall will be changed in order to be consistent with push/pop? i.e., will r10 be saved in stack before a (v)call?will r10 be copied to r1 before a call (in order to not overwrite the stack)?

@gut
Copy link
Author

gut commented Sep 17, 2015

This push/pop operations are not specifically for HHVM (as you point out about vret and vcall). On the proposal it says "When branching out of the function"... The source code related to that are 54-68.

As you see on line #58, yes, it's saved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment