Reputation: 1465
I have a c file contains this program
#include <stdio.h>
#include "traceback.h"
void bar(int x, int y)
{
int z;
z = x + y;
traceback(stdout);
x = z;
}
void foo() {
bar (5,17);
}
int main (int argc, char **argv)
{
foo();
return 0;
}
traceback(FILE *out)
is in traceback.c
When I print out the starting address of each function, I get this
function in table name: _init 0x80481c0
function in table name: is_trusted_path_normalize 0x80487c8
function in table name: strip 0x80488b2
function in table name: group_number 0x8048968
function in table name: _i18n_number_rewrite 0x8048a14
function in table name: fini 0x8048b30
function in table name: init_cacheinfo 0x8048b40
function in table name: _start 0x8048d68
function in table name: __x86.get_pc_thunk.bx 0x8048d90
function in table name: deregister_tm_clones 0x8048da0
function in table name: register_tm_clones 0x8048dd0
function in table name: __do_global_dtors_aux 0x8048e10
function in table name: frame_dummy 0x8048e40
function in table name: bar 0x8048e84
function in table name: foo 0x8048eaa
function in table name: main 0x8048ec6
function in table name: traceback 0x8048ed8
function in table name: __libc_start_main 0x8048f30
function in table name: check_one_fd 0x80491e0
function in table name: __libc_check_standard_fds 0x80492d0
I have no idea why traceback
have a higer address than main
. Shouldn't it lower than bar
? As bar
is the one calling traceback
?
This is my traceback.c
#include "traceback_internal.h"
void traceback(FILE *fp)
{
int i;
for(i=0; i < 20; i++){
printf(" function in table name: %s %p\n", functions[i].name, functions[i].addr);
}
}
where functions
is a global table that store information for each functions.
Upvotes: 0
Views: 166
Reputation: 901
try this inside gdb
x/24xw $esp
this means examine 24 hexadecimal words(words = 4bytes) this will print 24hex words starting add the current address of the stack this is essentially printing out your stack.
x/24xb $esp examine 24 hex bytes, x/24tb examine 24binary bytes and soo on
x/24xb you will find that your function variables are in the order you expect, the first functions vairalbes will be in higher addresses
A compiled program’s memory is divided into five segments: text, data, bss, heap, and stack. Each segment represents a special portion of memory that is set aside for a certain purpose. The text segment is also sometimes called the code segment. This is where the assembled machine language instructions of the program are located. The execution of instructions in this segment is nonlinear, thanks to the aforementioned high-level control structures and functions, which compile into branch, jump, and call instructions in assembly language. As a program executes, the EIP is set to the first instruction in the text segment(EIP points to the text segment while ESP poitns to the stack note the differece you have combined ESP and EIP together, they are completely different the code live on the text/data segment) while the function variables lives on the stack**. The processor then follows an execution loop that does the following: 1. Reads the instruction that EIP is pointing to 2. Adds the byte length of the instruction to EIP 3. Executes the instruction that was read in step 1 4. Goes back to step 1 Sometimes the instruction will be a jump or a call instruction, which changes the EIP to a different address of memory. The processor doesn’t care about the change, because it’s expecting the execution to be nonlinear anyway. If EIP is changed in step 3, the processor will just go back to step 1 and read the instruction found at the address of whatever EIP was changed to.
Upvotes: 0
Reputation: 213606
Shouldn't it lower than bar? As bar is the one calling traceback?
You are confusing stack layout with code layout.
Stack exists only at runtime.
Code is laid out during linking, and that's when addresses of functions are determined by the linker. The linker usually doesn't care which function calls which other function [1], it merely takes the object files given to it, and concatenates various sections (.text
, .data
, etc.) from these object files together, to form the final executable (or shared library).
You are determining function addresses at runtime, but you could just as easily run nm a.out
to get the same result without running the binary.
If you wanted to understand the runtime layout of function frames (which will contain return address to the caller inside callee), you should print __builtin_return_address(0)
. That is more likely to produce results you are looking for.
[1] There are linker optimizations that try to place functions that call each other close together in the .text
segment in order to minimize TLB misses, but it's unlikely that you'll know what that means.
Upvotes: 1
Reputation: 272527
Shouldn't it lower than
bar
? Asbar
is the one callingtraceback
?
No. Code doesn't live on the stack. If you were to examine the cal-stack, things would be different (depending on the conventions of your compiler/platform).
Upvotes: 2