pgubook-readers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Pgubook-readers] Chapt 9 - Correct Stack Layout


From: Mark Schmid
Subject: [Pgubook-readers] Chapt 9 - Correct Stack Layout
Date: Sun, 30 Sep 2007 15:24:40 +0200

Hi all,

Chapter 9, Correct Stack Layout
Page 149, 151 in book

I know Ruben has already mentioned this, but since Jon doesn't post his error 
corrections to the list but replies by email, I still didn't know how the 
actual stack layout is after a program is started by LINUX.

So instead of doing the "Use the Concepts" exercises (yes, I *confess*, I'm 
bumming up on those now, those REALLY eat up your time!!), I made a little 
program which shows what's on the stack, "showstack.s".

Here's what I found out with it:
In the book, page 92 (end of chapter 5) is correct.
The text on page 149 (chapter 9, "The Memory Layout of a Linux Program") is 
completely messed up. The graphic of the stack on page 151 however is correct 
again.

Here's the correct stack layout in words (for page 149):

At the bottom of the stack (first in) are various environment variables (each 
using an own stack position).
After that there is a word of memory that is zero.
Then come the program's command line arguments (or the "argv" array, which 
includes all arguments, even the program name), from last to first, each in a 
separate stack position.
The last "argument" of the argv array written to the stack is the program's 
name.
And finally, at the very end, we have the number of elements in the argv array 
(the number of command line arguments, including the program name).

You can test it yourself.
Here's my little program to tinker with.
Note that it needs the printf function from the C library, so after assembling 
it, you will have to link it with something like:
ld -dynamic-linker /lib/ld-linux.so.2 -o showstack.exe showstack.o -lc  

If the code seems excessively long for what it does, it's because
I'm sharing my source code template with you which is very handy
for large programs with deep conditional nesting.

-----------------------------
#23456789 123456789 123456789 123456789 123456789 123456789 1234567890 2
########################################################################
###             showstack.s - Print contents of stack to STDOUT      ###
########################################################################
## COPYLEFT:    Mark Schmid, Switzerland, 2007.10.01                  ##
##                                                                    ##
## PURPOSE:     Print the the contents of the stack right after       ##
##              program start to STDOUT to see what it REALLY is!     ##
##                                                                    ##
## REGISTERS:   CAUTION: Since printf uses the registers for its      ##
##                       processing, we MUST either use global        ##
##                       variables (symbols) OR save our registers to ##
##                       the stack before calling printf and then     ##
##                       pop them off the stack again after printf    ##
##                       has been called, otherwise we will have      ##
##                       GIBBERISH in our registers after printf was  ##
##                       called!                                      ##
##              %eax - Will be both the loop counter to loop          ##
##                     through all wanted stack positions as well     ##
##                     as hold the current stack position to print    ##
##                     inside the format string of the output.        ##
##                                                                    ##
## VARIABLES:   positions_to_print - Number of loop passes or stack   ##
##               positions to print (other than 0).                   ##
##              current_position - Holds the current position of the  ##
##               loop and stack because %eax gets deleted by printf.  ##
##              printf_string_posX - Different format strings for     ##
##               printf.                                              ##
##                                                                    ##
## ASSEMBLY:    To make the object code, type:                        ##
##              as showstack.s -o showstack.o                         ##
## LINKING:     To make the executable file type:                     ##
##              ld -dynamic-linker /lib/ld-linux.so.2 -o        /     ##
##              showstack.exe showstack.o -lc                         ##
## EXECUTING:   To execute, type: showstack.exe                       ##
##              Add any number of arguments to see what happens.      ##
##              Example: showstack.exe piff puff                      ##
########################################################################
##  SUMMARY:                                                          ##
##  --------                                                          ##
## 1.)                                                                ##
##  Include needed files.                                             ##
## 2.)                                                                ##
##  Define needed data.                                               ##     
## 3.)                                                                ##
##  Define needed buffers.                                            ##
## 4.)                                                                ##
##  Program-Logic.                                                    ##
########################################################################



########################################################################
## 1.)                                                                ##
##  Include needed files.                                             ##
########################################################################
# .include "linux.s"
########################################################################
## 1.) END                                                            ##
########################################################################



########################################################################
## 2.)                                                                ##
##  Define needed data.                                               ##     
########################################################################
.section .data

# Change this number to print more or less stack positins:
positions_to_print:
.long 9

# %eax will be restored from here after being overwritten by printf.
# Start printing at position 0:
current_position:
.long 0

printf_string_pos0:
.ascii "At stack position %d (=last in, LOWEST in RAM) (=# of Arguments): 
%d\n\0"
# Caution: Make sure everything after .ascii is on ONE line!

printf_string_pos1up:
.ascii "At stack positon -%d (counting UPwards in RAM!): %s\n\0"

########################################################################
## 2.) END                                                            ##
########################################################################



########################################################################
## 3.)                                                                ##
##  Define needed buffers.                                            ##
########################################################################
# Caution:      Buffers for reading and writing to files should never
#               exceed 16'000 bytes for various reasons.
#
# .section .bss
# .lcomm record_buffer, RECORD_SIZE
########################################################################
## 3.) END                                                            ##
########################################################################



########################################################################
## 4.)                                                                ##
##  Program-Logic.                                                    ##
## 4.1                                                                ##
##  Initialize program.                                               ##
## 4.2                                                                ##
##  Print stack position 0 outside of loop because this is the only   ##
##  position which uses a format string for printf with only numbers  ##
##  in it.                                                            ##
## 4.3                                                                ##
##  Loop through all stack positions that use the same format string  ##
##  for printf, printing each's content to STDOUT with printf.        ##
## 4.4                                                                ##
##  Exit program.                                                     ##
########################################################################

########################################################################
## 4.1                                                                ##
##  Initialize program.                                               ##
########################################################################

####### CONSTANTS #######
# Stack word size: This is the size in bytes of each stack position:
.equ STACK_WORDSIZE, 4

.section .text

# Make _start a global symbol so it will not be discarded by the
# assembler after assembly because the linker needs it to tell the
# kernel at which location execution should start:
.globl _start

# Mark the location of the symbol _start:
_start:

# Save the stack pointer's position at program start to %ebp
# to use as pointer to stack base for all this program's stack 
# variables:
movl %esp, %ebp

########################################################################
## 4.1 END                                                            ##
########################################################################



########################################################################
## 4.2                                                                ##
##  Print stack position 0 outside of loop because this is the only   ##
##  position which uses a format string for printf with only numbers  ##
##  in it.                                                            ##
########################################################################

# Move our current position stored in a global variable into 
# %eax (which can be overwritten by printf):
movl current_position, %eax


###### PRINT CURRENT STACK POSITION ######

# Put the last (3'rd) arguement for printf on the stack
# (what should be written at last %X of the format string).
# This is the actual 'content' of the stack position.
# We have %ebp pointing at the stack position at program start,
# To get the content of this loop pass's stack position, we use 
# indexed addressing mode:
# - start at %ebp, use index %eax with STACK_WORDSIZE:
pushl (%ebp, %eax, STACK_WORDSIZE)

# Put the second last (2'nd) arguement for printf on the stack
# (what should be written at second last %X of the format string).
# This is the stack position stored in %eax:
pushl %eax

# Put the first argument for printf on the stack (the format string):
# NOTE: We MUST do this outside loop, as this format string contains
#       two numbers. Trying to display a number as a string (%s)
#       with printf results in a segmentation fault when executing
#       the program.
pushl $printf_string_pos0       # Format string for printf

# Call printf (CAUTION: Overwrites most registers and ONLY restores
# the %ebp register according to the C calling convention!)
call printf

# Clean up stack, remove function arguments of printf:
addl $12, %esp

# Add 1 to our loop (and stack position) counter current_position:
incl current_position

########################################################################
## 4.2 END                                                            ##
########################################################################



########################################################################
## 4.3                                                                ##
##  Loop through all stack positions that use the same format string  ##
##  for printf, printing each's content to STDOUT with printf.        ##
## 4.3.1                                                              ##
##  Print current stack position to STDOUT using the C library        ##
##  function printf.                                                  ##
## 4.3.2                                                              ##
##  Check to see if we've made enough loop passes. If so, jump        ##
##  to end of loop.                                                   ##
## 4.3.3                                                              ##
##  Increase loop counter (stack position) by one and jump to         ##
##  beginning of loop.                                                ##
########################################################################
loop_begin:


########################################################################
## 4.3.1                                                              ##
##  Print current stack position to STDOUT using the C library        ##
##  function printf.                                                  ##
########################################################################

# Get the current value for the loop pass / stack position 
# stored in current_position and copy it to %eax (which was 
# overwritten by printf):
movl current_position, %eax


###### PRINT CURRENT STACK POSITION ######

# Put the last (3'rd) arguement for printf on the stack
# (what should be written at last %X of the format string).
# This is the actual 'content' of the stack position.
# We have %ebp pointing at the stack position at program start,
# To get the content of this loop pass's stack position, we use 
# indexed addressing mode:
# - start at %ebp, use index %eax with STACK_WORDSIZE:
pushl (%ebp, %eax, STACK_WORDSIZE)

# Put the second last (2'nd) arguement for printf on the stack
# (what should be written at second last %X of the format string).
# This is the stack position stored in %eax:
pushl %eax

# Put the first argument for printf on the stack (the format string):
# NOTE: We MUST do this outside loop, as this format string contains
#       two numbers. Trying to display a number as a string (%s)
#       with printf results in a segmentation fault when executing
#       the program.
pushl $printf_string_pos1up             # Format string for printf

# Call printf (CAUTION: Overwrites most registers and ONLY restores
# the %ebp register according to the C calling convention!)
call printf

# Clean up stack, remove function arguments of printf:
addl $12, %esp

########################################################################
## 4.3.1 END                                                          ##
########################################################################


########################################################################
## 4.3.2                                                              ##
##  Check to see if we've made enough loop passes. If so, jump        ##
##  to end of loop.                                                   ##
########################################################################
# Get the current value for the loop pass / stack position 
# stored in current_position and copy it to %eax (which was 
# overwritten by printf):
movl current_position, %eax

cmpl positions_to_print, %eax
# If second value is Equal to first value, quit by Jumping to loop_end:
jge loop_end
########################################################################
## 4.3.2 END                                                          ##
########################################################################


########################################################################
## 4.3.3                                                              ##
##  Increase loop counter (stack position) by one and jump to         ##
##  beginning of loop.                                                ##
########################################################################
# Add 1 to our loop / stack position counter:
incl current_position
# Jump to beginning of loop:
jmp loop_begin
########################################################################
## 4.3.3 END                                                          ##
########################################################################


loop_end:
########################################################################
## 4.3 END                                                            ##
########################################################################



########################################################################
## 4.4                                                                ##
##  Exit program.                                                     ##
########################################################################
# Move the number $SYS_EXIT ($1) into %eax to communicate the exit()
# system call:
movl $1, %eax
# Move the wanted return value number into %ebx:
movl positions_to_print, %ebx
# Call Linux by making the interrup for the kernel to interpret
# the system call in %eax:
int $0x80
########################################################################
## 4.4 END                                                            ##
########################################################################


########################################################################
## 4.) END                                                            ##
########################################################################
---------------------------

Greetings,
Mark
-- 
Psssst! Schon vom neuen GMX MultiMessenger gehört?
Der kanns mit allen: http://www.gmx.net/de/go/multimessenger




reply via email to

[Prev in Thread] Current Thread [Next in Thread]