void sub1(int32 p0, int16 p1, void *p2) { } Frame: [p2:4] <-- ebp+14 [p1:2] <-- ebp+12 [p0:4] <-- ebp+8 [retaddr:4] <-- ebp+4 [oldBP:4] <-- ebp+0 ... ... <-- esp use symbolic names p0 = 8 p1 = 12 p2 = 14 This is bad because any changes to the size of p0 means we have to manually change p1 and p2 p0_size = int16_size p1_size = char p2_size = addr_size p0 = retaddr + addr_size p1 = p0 + p0_size p2 = p1 + p1_size