Stack layouts

Burt Rosenberg
Sept 2012

The idea is to investigate how stack memory is laid out, including the placement of parameters, local storage (stack heap), the stack pointer, return address on the stack, and base pointer, including the stack frames.

The stack is layed out in frames. Each frame is a contiguous chunk of the stack and is the local memory for an instance of a function. As functions call each other, they form a call stack, and this is directly reflected as a stack of frames.

Data is accessed relative to either the stack pointer or the base pointer. The stack pointer decreases with a push operation and increases with a pop operation. It points to the next available space of memory on the stack (or maybe the last unavailable space). The base pointer is setup more deliberately by pushing the base pointer register onto the stack. Pushing this register closes the stack frame. You will create a new stack frame, with the base pointer pointing to the location of the old base pointer. This forms a linked list of base pointers that chain together the stack frames.

In IA-32 (x-86) architectures on linux, and in windows as well, the standard thing to do is to push the parameters to the call, then make the call, which pushes the return address. The subroutine called will close stack frame by pushing the old base pointer onto the stack, and then descend the stack by the needed amount to reserve space for function local variables.

Project 2, 2013 edition

A new set of examples and a project, new for the 2013 edition of Operating Systems. Following is the program.

#include<stdio.h> #include<stdlib.h> /* stacklist.c AN EXCERPT! by: burt date: 8 sep 2013 this project (1) helps student understand stack and stack frames (2) helps student understand how to manipulate pointers in C (3) helps student understand how to access memory locations directly (4) gives the student a chance to explore advance pointer concepts (5) practices the use of hexidecimal number representation (6) and a whole lot more! YEAH! You are to make a stack of recursive invocations of the function f and then print out the stack. Edit the file to indicate the parameters, local variables return address, and chain of base pointers. */ #define PRINTUP_COUNT 70 #define DEPTH 4 void printup( void * p ) { /* code removed .. this function prints a region of memory. see test.out for typical output. PRINTUP_COUNT is the number of words to print, starting at location p. */ return ; } void f(int c) { int i = c+0x0abc0000 ; int j = 0xdeafbeef ; if (c) f(c-1) ; else printup(&j) ; return ; } int main(int argc, char *argv[]) { printf("function f is at %p\n\n",f) ; f(DEPTH); return 0 ; }

The program out has been captured. Here it is. The goal is to get to know our way around the stack frames.

function f is at 0x8048462 0xbfbbfdec 00000000 0xbfbbfde8 bfbbfe6c 0xbfbbfde4 bfbbfe1c 0xbfbbfde0 00000000 0xbfbbfddc 40024858 0xbfbbfdd8 bfbbfe6c 0xbfbbfdd4 bfbbfe64 0xbfbbfdd0 00000001 0xbfbbfdcc 400444d3 0xbfbbfdc8 00000000 0xbfbbfdc4 00000000 0xbfbbfdc0 080484d0 0xbfbbfdbc 401cfff4 0xbfbbfdb8 080484d9 0xbfbbfdb4 08048462 0xbfbbfdb0 00000004 0xbfbbfdac 080484c7 0xbfbbfda8 bfbbfdc8 0xbfbbfda4 40021918 0xbfbbfda0 080485a9 0xbfbbfd9c 0abc0004 0xbfbbfd98 deadbeef 0xbfbbfd94 080485a9 0xbfbbfd90 401d0a20 0xbfbbfd8c 40077eff 0xbfbbfd88 bfbbfdc8 0xbfbbfd84 00000000 0xbfbbfd80 00000003 0xbfbbfd7c 0804848e 0xbfbbfd78 bfbbfda8 0xbfbbfd74 400315e8 0xbfbbfd70 bfbc093d 0xbfbbfd6c 0abc0003 0xbfbbfd68 deadbeef 0xbfbbfd64 bfbbfdb4 0xbfbbfd60 0804821c 0xbfbbfd5c 00000000 0xbfbbfd58 00000000 0xbfbbfd54 00000000 0xbfbbfd50 00000002 0xbfbbfd4c 0804848e 0xbfbbfd48 bfbbfd78 0xbfbbfd44 00000001 0xbfbbfd40 00000001 0xbfbbfd3c 0abc0002 0xbfbbfd38 deadbeef 0xbfbbfd34 4000e29b 0xbfbbfd30 00000000 0xbfbbfd2c 00000001 0xbfbbfd28 40021918 0xbfbbfd24 40020ff4 0xbfbbfd20 00000001 0xbfbbfd1c 0804848e 0xbfbbfd18 bfbbfd48 0xbfbbfd14 00000000 0xbfbbfd10 ffffffff 0xbfbbfd0c 0abc0001 0xbfbbfd08 deadbeef 0xbfbbfd04 40021a74 0xbfbbfd00 bfbbfd88 0xbfbbfcfc 40024858 0xbfbbfcf8 400315e8 0xbfbbfcf4 40009ed9 0xbfbbfcf0 00000000 0xbfbbfcec 0804848e 0xbfbbfce8 bfbbfd18 0xbfbbfce4 40020ff4 0xbfbbfce0 bfbbfd18 0xbfbbfcdc 0abc0000 0xbfbbfcd8 deadbeef

Big and Little Endian Computing

#include<stdio.h> #include<stdlib.h> /* A program to explore endianess, and hexidecimal Author: Burt Rosenberg Created: September 2013 Last update: */ void printbyte(char c) { static char *s = "0123456789abcdef" ; printf("%c%c", s[(c>>4)&15],s[c&15]) ; // printf("%02x",c) ; // the easy way } void printshort(short h, int bigendian) { /* done in a way to show endianess */ if (bigendian) { printbyte(*((char*)&h)) ; printbyte(*((char*)&h+1)); } else { printbyte(*((char*)&h+1)); printbyte(*((char*)&h)) ; } } void printword(int i, int bigendian) { if (bigendian) { printshort(*((short*)&i),bigendian) ; printshort(*((short*)&i+1),bigendian) ; } else { printshort(*((short*)&i+1),bigendian) ; printshort(*((short*)&i),bigendian) ; } } int isbigendian() { return ( htons(1)==1 ) ; } void test() { printf("Testing printbyte\nShould print 12: ") ; printbyte(0x12) ; printf("\n") ; printf("Testing printshort\nShould print 1234: ") ; printshort(0x1234,isbigendian()) ; printf("\n") ; printf("Testing printshort\nShould print 3412: ") ; printshort(0x1234,!isbigendian()) ; printf("\n") ; printf("Testing printshort\nShould print 1234: ") ; printshort(htons(0x1234),!isbigendian()) ; printf("\n") ; printf("Testing printword\nShould print 12345678: ") ; printword(0x12345678,isbigendian()) ; printf("\n") ; printf("Testing printword\nShould print 78563412: ") ; printword(0x12345678,!isbigendian()) ; printf("\n") ; printf("Testing printword\nShould print 12345678: ") ; printword(htonl(0x12345678),!isbigendian()) ; printf("\n") ; } int main(int argc, char * argv[]) { char * s1 = "type\tsize\nchar\t%d\nshort\t%d\nint\t%d\nlong\t%d\n" ; printf(s1,sizeof(char),sizeof(short),sizeof(int),sizeof(long)) ; if (isbigendian()) printf("Big Endian architecture\n") ; else printf("Little Endian architecture\n") ; test() ; return 0 ; }
Matawan:proj2 burt$ ./endian type size char 1 short 2 int 4 long 8 Little Endian architecture Testing printbyte Should print 12: 12 Testing printshort Should print 1234: 1234 Testing printshort Should print 3412: 3412 Testing printshort Should print 1234: 1234 Testing printword Should print 12345678: 12345678 Testing printword Should print 78563412: 78563412 Testing printword Should print 12345678: 12345678