如何在终端中使用GDB(GNU调试器)和OpenOCD进行微控制器调试?

73
使用插件连接Eclipse是编程ARM微控制器的标准低成本方法。Eclipse确实有其优点,但我想独立于此IDE。我想要了解在构建(编译-链接-刷写)我的软件时发生的情况以及运行调试会发生什么。为了获得这样更深入的理解,从命令行运行整个过程将会很好。
注意:我使用的是64位Windows 10。但是这里解释的大部分内容也适用于Linux系统。请以管理员身份打开所有命令终端。这可以避免出现许多问题。
1. 构建软件
第一个"任务"完成了。我现在能够通过命令行将我的软件编译和链接成二进制.bin.elf映像。成功的关键是找到Eclipse为特定项目放置其make文件的位置。一旦你知道它们在哪里,你所要做的就是打开一个命令终端,并键入GNU make命令。 enter image description here 这样你就不再需要Eclipse了!尤其是当你的项目不断发展时,如果你能阅读(并理解)makefile并调整它以满足你的需求。
请注意,我在安装STM32系统工作台(SW4STM32)后,在以下文件夹中找到了GNU工具(编译器、链接器、make实用程序、GDB等)。
C:\Ac6\SystemWorkbench\plugins\fr.ac6.mcu.externaltools.arm-none.win32_1.7.0.201602121829\tools\compiler\

接下来我在我的硬盘上创建了一个新文件夹,并将所有这些GNU工具复制到其中:

C:\Apps\AC6GCC
           |-> arm-none-eabi
           |-> bin
           '-> lib

我将这些条目添加到"环境变量"中的路径:

 - C:\Apps\AC6GCC\bin
 - C:\Apps\AC6GCC\lib\gcc\arm-none-eabi\5.2.1

太好了,现在我系统上所有的GNU工具都运行良好!我把以下build.bat文件放在与makefile相同的文件夹中:

@echo off
echo.
echo."--------------------------------"
echo."-           BUILD              -"
echo."--------------------------------"
echo.

make -j8 -f makefile all

echo.

运行这个批处理文件应该就可以了!如果一切顺利,编译结果应该会得到一个 .bin 和一个 .elf 二进制文件。

2. 烧录和调试固件

自然的下一步是烧录固件到芯片并开始调试。在Eclipse中,只需点击一个按钮 - 至少如果Eclipse为您的微控制器正确配置。但背后发生了什么呢? 我曾经阅读了Dominic Rath的硕士论文(OpenOCD开发人员的一部分)。您可以在这里找到它:http://openocd.net/。这是我学到的:

  • 当您单击“调试”图标时,Eclipse启动OpenOCD软件。Eclipse还向OpenOCD提供了一些配置文件,以便OpenOCD知道如何连接到您的微控制器。'如何连接'并不是一件简单的事情。 OpenOCD需要找到适当的USB驱动程序来连接JTAG适配器(例如STLink)。 JTAG适配器及其USB驱动程序通常由您的芯片制造商(例如STMicroelectronics)提供。 Eclipse还将一个描述微控制器规格的配置文件传递给OpenOCD。一旦OpenOCD知道了所有这些事情,它就可以与目标设备建立可靠的JTAG连接。

  • OpenOCD启动两个服务器。第一个是TCP端口4444上的Telnet服务器。它提供对OpenOCD CLI(命令行界面)的访问。Telnet客户端可以连接并向OpenOCD发送命令。那些命令可能是简单的“停止”,“运行”,“设置断点”等。

  • 这些命令可能足以调试您的微控制器,但是许多人已经熟悉GNU调试器(GDB)。这就是为什么OpenOCD还会在TCP端口3333上启动GDB服务器的原因。GDB客户端可以连接到该端口,并开始调试微控制器!

  • GNU调试器是一种命令行软件。许多人更喜欢可视化界面。这正是Eclipse所做的。 Eclipse启动一个连接到OpenOCD的GDB客户端 - 但对用户来说这一切都是隐藏的。 Eclipse提供一个图形界面,用于与幕后的GDB客户端交互。

我制作了一张图片来解释所有这些:

enter image description here

>> 启动OpenOCD

我成功从命令行启动了OpenOCD。我会解释一下如何操作。

  1. First make sure that your STLink-V2 JTAG programmer is properly installed. You can test the installation with the "STLink Utility tool" from STMicroelectronics. It has a nice GUI, and you simply click the connect button. enter image description here
  2. Next download the OpenOCD software executable from this website: http://gnutoolchains.com/arm-eabi/openocd/ . Install it, and put it in a folder on your harddrive, like "C:\Apps\".
  3. Open a command terminal, and start OpenOCD. You will need to give OpenOCD a few configuration files, such that it knows where to look for your microcontroller. Typically you need to give a configuration file that describes the JTAG programmer, and a configuration file that defines your microcontroller. Pass those files to OpenOCD with the -f argument in the command line. You will also need to give OpenOCD access to the scripts folder, by passing it with the -s argument. This is how I start OpenOCD on my computer with the command line:

    > "C:\Apps\OpenOCD-0.9.0-Win32\bin\openocd" -f "C:\Apps\OpenOCD-0.9.0-Win32\share\openocd\scripts\interface\stlink-v2.cfg" -f "C:\Apps\OpenOCD-0.9.0-Win32\share\openocd\scripts\target\stm32f7x.cfg" -s "C:\Apps\OpenOCD-0.9.0-Win32\share\openocd\scripts"
    
  4. If you started OpenOCD properly (with the correct arguments), it will startup with the following message:

    Open On-Chip Debugger 0.9.0 (2015-08-15-12:41)
    Licensed under GNU GPL v2
    For bug reports, read
            http://openocd.org/doc/doxygen/bugs.html
    Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
    Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
    adapter speed: 2000 kHz
    adapter_nsrst_delay: 100
    srst_only separate srst_nogate srst_open_drain connect_deassert_srst
    Info : Unable to match requested speed 2000 kHz, using 1800 kHz
    Info : Unable to match requested speed 2000 kHz, using 1800 kHz
    Info : clock speed 1800 kHz
    Info : STLINK v2 JTAG v24 API v2 SWIM v4 VID 0x0483 PID 0x3748
    Info : using stlink api v2
    Info : Target voltage: 3.231496
    Info : stm32f7x.cpu: hardware has 8 breakpoints, 4 watchpoints
    Info : accepting 'gdb' connection on tcp/3333
    Info : flash size probed value 1024
    
  5. Notice that your terminal window is now blocked. You can no longer type commands. But that's normal. OpenOCD is running in the background, and it blocks the terminal. Now you've got two options to interact with OpenOCD: you start a Telnet session in another terminal, and you log on to TCP port localhost:4444, so you can give commands to OpenOCD and receive feedback. Or you start a GDB client session, and connect it to TCP port localhost:3333.

>> 启动Telnet会话与OpenOCD进行交互

以下是与正在运行的OpenOCD程序进行交互的Telnet会话启动方式:

> dism /online /Enable-Feature /FeatureName:TelnetClient

> telnet 127.0.0.1 4444

如果一切正常,您的终端将显示以下消息:
Open On-Chip Debugger
> ..

现在您已经可以向OpenOCD发送命令了!但是我将切换到GDB会话,因为这是与OpenOCD交互最方便的方式。

>> 启动一个GDB客户端会话以与OpenOCD交互

打开另一个终端窗口,并输入以下命令:

> "C:\Apps\AC6GCC\bin\arm-none-eabi-gdb.exe"

这个命令只是启动了 arm-none-eabi-gdb.exe GDB客户端。如果一切顺利,GDB会启动并显示以下信息:
    GNU gdb (GNU Tools for ARM Embedded Processors) 7.10.1.20151217-cvs
    Copyright (C) 2015 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "--host=i686-w64-mingw32 --target=arm-none-eabi".
    Type "show configuration" for configuration details.
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>.
    Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.
    For help, type "help".
    Type "apropos word" to search for commands related to "word".
    (gdb)..

现在将这个GDB客户端连接到OpenOCD内部的GDB服务器:

    (gdb) target remote localhost:3333

现在您已连接到OpenOCD!需要注意的是:如果您想使用本机OpenOCD命令(就像在Telnet会话中一样),只需在命令前加上关键字monitor。这样,OpenOCD内部的GDB服务器将不会自己处理该命令,而是传递给本机OpenOCD守护程序。
现在,是时候重置芯片、擦除并停止了:
    (gdb) monitor reset halt
       target state: halted
       target halted due to debug-request, current mode: Thread
       xPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc
    (gdb) monitor halt

    (gdb) monitor flash erase_address 0x08000000 0x00100000
       erased address 0x08000000 (length 1048576) in 8.899024s (115.069 KiB/s)
    (gdb) monitor reset halt
       target state: halted
       target halted due to debug-request, current mode: Thread
       xPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc
    (gdb) monitor halt

芯片现在已准备好接受我们的指令。首先,我们将告诉芯片它的闪存区段0到7(即我的1Mb芯片中的所有闪存区段)不应受到保护:
    (gdb) monitor flash protect 0 0 7 off

    (gdb) monitor flash info 0
       #0 : stm32f7x at 0x08000000, size 0x00100000, buswidth 0, chipwidth 0
            #  0: 0x00000000 (0x8000 32kB) not protected
            #  1: 0x00008000 (0x8000 32kB) not protected
            #  2: 0x00010000 (0x8000 32kB) not protected
            #  3: 0x00018000 (0x8000 32kB) not protected
            #  4: 0x00020000 (0x20000 128kB) not protected
            #  5: 0x00040000 (0x40000 256kB) not protected
            #  6: 0x00080000 (0x40000 256kB) not protected
            #  7: 0x000c0000 (0x40000 256kB) not protected

接下来,我再次停止芯片。只是为了确保一下..

    (gdb) monitor halt

最后我将二进制文件.elf交给GDB:

    (gdb) file C:\\..\\myProgram.elf
       A program is being debugged already.
       Are you sure you want to change the file? (y or n) y
       Reading symbols from C:\..\myProgram.elf ...done.

现在是真正的时刻。 我要求GDB将此二进制文件加载到芯片中。 手指交叉:

    (gdb) load
       Loading section .isr_vector, size 0x1c8 lma 0x8000000
       Loading section .text, size 0x39e0 lma 0x80001c8
       Loading section .rodata, size 0x34 lma 0x8003ba8
       Loading section .init_array, size 0x4 lma 0x8003bdc
       Loading section .fini_array, size 0x4 lma 0x8003be0
       Loading section .data, size 0x38 lma 0x8003be4
       Error finishing flash operation

可惜没有成功。在 OpenOCD 中,我收到了以下信息:

    Error: error waiting for target flash write algorithm
    Error: error writing to flash at address 0x08000000 at offset 0x00000000

编辑:硬件问题已解决。

显然这是一个硬件问题。我从未想过芯片会有缺陷,因为使用STLink Utility工具将二进制文件加载到芯片上时没有问题。只有OpenOCD在抱怨和出错。所以自然而然地我责怪了OpenOCD - 而不是芯片本身。请参阅下面的答案获取更多详细信息。


编辑:另一种优雅的闪存芯片方法 - 使用makefile!

问题得到解决后,我现在将专注于执行芯片的闪存和调试的另一种替代方式。我相信这对社区来说非常有趣!

您可能已经注意到,我使用Windows cmd命令来执行所有必要的步骤。这可以在批处理文件中自动化处理。但是有一种更优雅的方式:在makefile中自动化处理一切!Othane先生/女士已经为他/她的Cortex-M?芯片提供了以下makefile。我想Cortex-M7芯片的程序非常相似:

            #################################################
            #        MAKEFILE FOR BUILDING THE BINARY       #
            #        AND EVEN FLASHING THE CHIP!            #
            # Author: Othane                                #
            #################################################

    # setup compiler and flags for stm32f373 build 
    SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST))) 


    CROSS_COMPILE ?= arm-none-eabi- 
    export CC = $(CROSS_COMPILE)gcc 
    export AS = $(CROSS_COMPILE)gcc -x assembler-with-cpp 
    export AR = $(CROSS_COMPILE)ar 
    export LD = $(CROSS_COMPILE)ld 
    export OD   = $(CROSS_COMPILE)objdump 
    export BIN  = $(CROSS_COMPILE)objcopy -O ihex 
    export SIZE = $(CROSS_COMPILE)size 
    export GDB = $(CROSS_COMPILE)gdb 


    MCU = cortex-m4 
    FPU = -mfloat-abi=hard -mfpu=fpv4-sp-d16 -D__FPU_USED=1 -D__FPU_PRESENT=1 -DARM_MATH_CM4 
    DEFS = -DUSE_STDPERIPH_DRIVER -DSTM32F37X -DRUN_FROM_FLASH=1 -DHSE_VALUE=8000000 
    OPT ?= -O0  
    MCFLAGS = -mthumb -mcpu=$(MCU) $(FPU) 


    export ASFLAGS  = $(MCFLAGS) $(OPT) -g -gdwarf-2 $(ADEFS) 
    CPFLAGS += $(MCFLAGS) $(OPT) -gdwarf-2 -Wall -Wno-attributes -fverbose-asm  
    CPFLAGS += -ffunction-sections -fdata-sections $(DEFS) 
    export CPFLAGS 
    export CFLAGS += $(CPFLAGS) 


    export LDFLAGS  = $(MCFLAGS) -nostartfiles -Wl,--cref,--gc-sections,--no-warn-mismatch $(LIBDIR) 


    HINCDIR += ./STM32F37x_DSP_StdPeriph_Lib_V1.0.0/Libraries/CMSIS/Include/ \ 
        ./STM32F37x_DSP_StdPeriph_Lib_V1.0.0/Libraries/CMSIS/Device/ST/STM32F37x/Include/ \ 
        ./STM32F37x_DSP_StdPeriph_Lib_V1.0.0/Libraries/STM32F37x_StdPeriph_Driver/inc/ \ 
        ./ 
    export INCDIR = $(patsubst %,$(SELF_DIR)%,$(HINCDIR)) 




    # openocd variables and targets 
    OPENOCD_PATH ?= /usr/local/share/openocd/ 
    export OPENOCD_BIN = openocd 
    export OPENOCD_INTERFACE = $(OPENOCD_PATH)/scripts/interface/stlink-v2.cfg 
    export OPENOCD_TARGET = $(OPENOCD_PATH)/scripts/target/stm32f3x_stlink.cfg 


    OPENOCD_FLASH_CMDS = '' 
    OPENOCD_FLASH_CMDS += -c 'reset halt' 
    OPENOCD_FLASH_CMDS += -c 'sleep 10'  
    OPENOCD_FLASH_CMDS += -c 'stm32f1x unlock 0' 
    OPENOCD_FLASH_CMDS += -c 'flash write_image erase $(PRJ_FULL) 0 ihex' 
    OPENOCD_FLASH_CMDS += -c shutdown 
    export OPENOCD_FLASH_CMDS 


    OPENOCD_ERASE_CMDS = '' 
    OPENOCD_ERASE_CMDS += -c 'reset halt' 
    OPENOCD_ERASE_CMDS += -c 'sleep 10'  
    OPENOCD_ERASE_CMDS += -c 'sleep 10'  
    OPENOCD_ERASE_CMDS += -c 'stm32f1x mass_erase 0' 
    OPENOCD_ERASE_CMDS += -c shutdown 
    export OPENOCD_ERASE_CMDS 


    OPENOCD_RUN_CMDS = '' 
    OPENOCD_RUN_CMDS += -c 'reset halt' 
    OPENOCD_RUN_CMDS += -c 'sleep 10' 
    OPENOCD_RUN_CMDS += -c 'reset run' 
    OPENOCD_RUN_CMDS += -c 'sleep 10'  
    OPENOCD_RUN_CMDS += -c shutdown 
    export OPENOCD_RUN_CMDS 


    OPENOCD_DEBUG_CMDS = '' 
    OPENOCD_DEBUG_CMDS += -c 'halt' 
    OPENOCD_DEBUG_CMDS += -c 'sleep 10' 


    .flash: 
        $(OPENOCD_BIN) -f $(OPENOCD_INTERFACE) -f $(OPENOCD_TARGET) -c init $(OPENOCD_FLASH_CMDS) 


    .erase: 
        $(OPENOCD_BIN) -f $(OPENOCD_INTERFACE) -f $(OPENOCD_TARGET) -c init $(OPENOCD_ERASE_CMDS) 


    .run: 
        $(OPENOCD_BIN) -f $(OPENOCD_INTERFACE) -f $(OPENOCD_TARGET) -c init $(OPENOCD_RUN_CMDS) 


    .debug: 
        $(OPENOCD_BIN) -f $(OPENOCD_INTERFACE) -f $(OPENOCD_TARGET) -c init $(OPENOCD_DEBUG_CMDS) 

尊敬的Othane先生/女士:

能否请您解释一下如何使用这个makefile来完成以下步骤:

  • 从源代码编译二进制文件
  • 刷写芯片

我对makefile有一些基本了解,但是您的makefile确实很深奥。您似乎使用了GNU make工具的很多功能。请给我们一些更多的解释,我会给您额外的奖励;-)


1
所示的 makefile 实际上并不太复杂...基本上我每个架构都有一个这样的文件,它会导出许多变量,如 CC 和 CFLAGS 到包含它的较低级的 makefile 中,它们可以使用这些标志来通用地编译代码...在编程方面,我们只需要添加一些.erase、.flash 等命令,因此要进行完全擦除程序等操作,您可能需要运行:make .erase && make .flash && make .debug ...然后您就可以连接 gdb,或者运行 make .run 以无调试运行。 - othane
哇,非常感谢你的帮助。我可以再求你一个小小的忙吗?不仅是为了我,还有那些能从你精彩答案中受益的人们。你可以在你的回答中复制适用于Cortex-M7/M4的那些makefile(即“父级”和“子级”makefile)吗?同时也能提供使用它们的命令吗?那将真是太棒了!社区会因此而感激你的:-) (提供Github的参考链接也不错,但最好让所有内容都在StackOverflow上可见。这样更易获取,并且人们可以留下评论、提问...) - K.Mulier
嗨@othane,我已经向您授予了奖金。您真的值得拥有它!请考虑将您的makefiles放在StackOverflow上的想法。我会非常高兴 :-) - K.Mulier
谢谢,伙计。很抱歉我错过了这条消息,我不认为这是发布文件的好地方...它们应该都在GitHub上可用,我觉得那里比stackoverflow更合适。 - othane
很棒的问题! - smwikipedia
5个回答

10
据我所记,我也曾在使用直接加载命令时遇到了一些麻烦,因此我转而使用了“flash write_image erase my_project.hex 0 ihex”命令。显然,我正在使用hex文件,但是似乎elf文件也可以工作,参见http://openocd.org/doc/html/Flash-Commands.html。这个命令的好处是它还会擦除只被写入的flash部分,这非常方便,而且你不需要进行擦除操作。
在运行上述命令之前,您需要运行“stm32f1x unlock 0”以确保芯片已解锁并且允许你连接到flash,请参见Datasheet相关内容。
此外,为了开始使用,命令“stm32f1x mass_erase 0”将完全快速地擦除芯片,因此最好确保您处于已知状态。
我知道其中一些命令说它们是针对F1的,但请相信我,它们也适用于F4系列。
顺便说一下,该文件包含了我用来刷我的F4的大部分命令,因此它可能是一个很好的参考 https://github.com/othane/mos/blob/master/hal/stm32f373/stm32f373.mk 希望这能够帮助到您。

嗨othane,非常感谢。我明天会尝试一下。我注意到在将图像写入芯片之前,你放置了一些命令。像一个“睡眠”命令。它是用来做什么的? - K.Mulier
这是我写的有一段时间了,但我记得它是为了在我使用的所有不同编程器上可靠地工作,例如STM SWD、blink JTAG等等... 没有它,我想有时会出现连接错误... 不过现在可能已经在openocd中修复了这个问题。 - othane
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - K.Mulier
很酷,很高兴你已经运行起来了!!我在想可能不是硬件问题...你尝试使用“stm32f1x mass_erase 0”和“flash write_image erase blah.elf 0”命令了吗?我在想可能是某个选项字节被卡住了,或者闪存以其他方式受到保护,因此使用stm例程进行完全擦除和刷写可能会使其恢复正常(特别是如果您第一次成功编程芯片)。 - othane

3
乍一看,在gnutoolchains.com上分发应该足够好了。有许多构建脚本可以用来制作自己的版本。我已经拥有了我的版本,包括ARM7TDMI。它在Linux和FreeBSD下工作正常,但我上次尝试MinGW时失败了 :-(
关于OpenOCD,我建议在与您的GDB实例相同的目录中启动它,这样如果您从GDB中调用它,则二进制下载似乎是透明的(最简单的方法)。您还可以选择创建一个启动OpenOCD并加载代码的脚本,但然后您将不得不在每次编译后重新启动它。

谢谢@O. Gautherot。这真的很有帮助 :-) - K.Mulier
嗨@O. Gautherot,我取得了很大的进展,离成功只差一步之遥。请查看我的问题更新。不幸的是,在闪存过程的末尾我遇到了一个错误。如果您有建议,请帮助我。非常感谢。 - K.Mulier

3
这段文字是关于编程的,作者分享了他的代码库并提供了链接。他的项目是一个Makefile树,并提供了一些命令来擦除芯片、刷写和调试代码等功能。你可以在https://github.com/othane/mos找到他的代码,而主要的Makefile则在https://github.com/othane/mos/blob/master/hal/stm32f373/stm32f373.mk中。
最后,如果您查看我的单元测试(这些基本上是示例程序),您将找到Makefile以构建它+类似于此https://github.com/othane/mos/blob/master/utest/gpio/debug_gpio_utest.gdbinit的gdbinit文件...然后您只需在一个终端中执行“make && make .flash && make .debug”,并像这样调用您的交叉编译器gdb“arm-none-eabi-gdb -x ./debug_gpio_utest.gdbinit”在另一个终端中...这将在刷新代码后启动gdb,并且您可以使用来自gdb等的常规中断和列表命令与代码交互(请注意我如何在.gdbinit文件中定义重置命令,请查看mon命令的帮助......基本上它将允许您直接通过gdb向openocd发送命令,非常有用)。
抱歉,答案很简短,包含很多链接,但我希望它能让您开始。

嗨@othane,我取得了很多进展,离成功已经不远了。请查看我的问题更新。可惜在闪存过程的最后出现了一个错误。如果您有建议,请帮助我。非常感谢。 - K.Mulier
请看我的回答以使闪烁效果工作......抱歉这里放不下 ;) ... 希望能有所帮助。 - othane

1
你现在只需要调用"gdb"并将其连接到“远程服务器”(如果服务器和gdb在同一台机器上,则为localhost)。配置GDB以使其知道源代码的位置和ELF文件的位置。有很多网站介绍GDB的基本用法。
似乎有一个适用于Windows的GDB(http://www.equation.com/servlet/equation.cmd?fa=gdb)。
以下是GDB中的命令,可帮助您入门:
target remote localhost:3333
directory /path/to/project
symbol-file /path/to/project.elf

非常感谢。我从这个网站 http://gnutoolchains.com/arm-eabi/ 下载了 Windows 版本的 GDB。你觉得它与从 http://www.equation.com/servlet/equation.cmd?fa=gdb 得到的那个相比如何? - K.Mulier

0

显然这是一个硬件问题。我从未想过我的芯片会有缺陷,因为使用STLink Utility工具将二进制文件加载到芯片上没有任何问题。只有OpenOCD在抱怨并给出错误。所以自然而然地,我责怪了OpenOCD - 而不是芯片本身。

今天我尝试在板子上使用新的芯片进行相同的操作,现在它可以正常工作了!

当我发出load命令时,在GDB中我得到以下输出:

    (gdb) load
       Loading section .isr_vector, size 0x1c8 lma 0x8000000
       Loading section .text, size 0x39e0 lma 0x80001c8
       Loading section .rodata, size 0x34 lma 0x8003ba8
       Loading section .init_array, size 0x4 lma 0x8003bdc
       Loading section .fini_array, size 0x4 lma 0x8003be0
       Loading section .data, size 0x38 lma 0x8003be4
       Start address 0x8003450, load size 15388
       Transfer rate: 21 KB/sec, 2564 bytes/write.
    (gdb)

感谢每一位尽力帮助我的人 :-)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接