Gdb调试Fortran中的堆和栈

转载自:http://blog.sina.com.cn/s/blog_7a1c18a80101fv4x.html

 

 

Gdb调试Fortran中的堆和栈

  (2014-02-27 15:24:03)

转载

标签: 

gdb

 

fortran

 

堆栈

分类: fortran

今天来讨论一下Fortran中的各种变量是如何在堆和栈中储存的。

有关堆(heap)和栈(stack)的概念可以去看斯坦福大学的开放课程:编程方法(Programming.Methodology.CS106A)。不过课堂上使用的是java语言,而且网上找不到有关Fortran语言中变量是如何在堆和栈中储存的。因此,本文中将使用一个简短的例子演示一下Fortran程序内部工作原理,顺便演示如何使用gnu中的gdb调试程序。

首先介绍如何使用gdb命令来查看函数及变量在内存的位置,gdb使用方法可参考《Linux C编程一站式学习》

Backtrace(bt)

查看调用函数的栈帧

Info(i)

查看局部变量:I locals

Frame(f)

选择栈帧

Finish

让当前函数运行,直到返回为止

Set var

改变变量值

X

打印储存单元内容,全部看做字节,而不区分是哪个变量的字节

 

写一个比较简单的程序,在main函数中调用sub1子函数,查看各个函数栈帧在内存中位置以及变量储存位置。

Gdb调试过程

各条命令详细解释:

  1. list展示源程序
  2. b 7    设置断点于源程序的第7行
  3. start    开始运行程序
  4. s = step,单步运行,运行到调用子程序时进入子程序
  5. bt    显示函数调用的栈帧
  6. i locals    显示当前函数局部变量
  7. f 1    返回栈帧为1的main函数
  8. i locals    显示main函数局部变量

 

查询内存存储情况

Examine memory: x/FMT ADDRESS.

ADDRESS is an expression for the memory address to examine.

FMT is a repeat count followed by a format letter and a size letter.

Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),t(binary), f(float), a(address), i(instruction), c(char) and s(string).

Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).

The specified number of objects of the specified size are printed according to the format.

 

Defaults for format and size letters are those previously used.

Default count is 1. Default address is following last thing printed with this command or "print".

 

根据说明可以看出,gdb中x的作用是显示内存地址中所储存的变量值。

都说变量名是函数地址的别名,但是x后面直接跟变量名并不能正确显示。

可以看到,第一次使用x/a temp运行时,会将变量temp的变量值10自动"替换"temp,从而显示的0xa地址。而只有使用了取址符号&后,才正确显示出函数地址处的变量值。

另外,在sub函数内查询U、V是无法正确查到地址以及变量值的,只有使用frame函数转到main函数的栈上,才能显示main函数的U、V变量。在sub函数内只有x、y、temp、z可正确查询。

变量

内存中位置(16进制)

值(16进制的地址格式)

U

0x28abfc

0x0000000a

V

0x28abf8

0x0000000b

W

0x28abf4

0x00000015

Temp

0x28aa74

0x0000000a

x

0x28abfc

0x0000000a

y

0x28abf8

0x0000000b

z

0x28abf4

0x00000015

 

从上面内存地址可以看出,fortran在传递参数时是按址传递,也就是直接传递实参的地址给子函数,这样子函数中参数的改变也会导致实参相应的改变。另外,在栈上是从高地址向低地址扩展的(0x28abfc→0x28abf4),可是子函数是哪里储存的,地址0x28aa74又是从何而来?

 

使用gdb反汇编命令disassemble,对主函数main和子函数sub进行反汇编查看。

这样查看有一个缺点,那就是无法与源程序对应,查看响应源程序语句的汇编命令。

使用$objdump –dS main命令,将源代码与汇编代码穿插显示。下面只截取main和sub函数部分。

使用watch $esp及watch $ebp指令,能够每步执行时查询栈顶及栈底指针变化情况。

指令

esp

ebp

0x00401199 <+9>

0x28aa80

0x28ac08

0x00401170 <+0> <-into sub

0x28aa7c

 

0x00401171

0x28aa78

 

0x00401173

 

0x28aa78

0x00401176 <+6>

0x28aa68

 

0x0040118f

0x28aa7c

0x28ac08

0x004011c0 <-return main

0x28aa80

 

0x00401264

0x28aa7c

 

 

从这里可以看出,main函数的栈帧是从0x28aa80→0x28ac08,而sub子函数栈帧为0x28aa68→0x28aa78。Temp变量储存位置为0x28aa74恰好位于sub子函数栈帧中。

各个函数栈帧示意图:

0x28ac08

main函数栈底

……

 

0x28abfc

U储存位置

0x28abf8

V储存位置

0x28abf4

W

……

 

0x28aa80

main函数栈顶

……

 

0x28aa78

sub函数栈底

……

 

0x28aa68

sub函数栈顶

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值