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函數棧頂

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章