【问题标题】:The variable name defined in .bss section can not be found in gdb在 gdb 中找不到 .bss 部分中定义的变量名
【发布时间】:2017-06-30 08:46:30
【问题描述】:

我正在尝试一个简单的汇编代码:

.section .data
output:
    .ascii "The processor Vendor ID is 'xxxxxxxxxxxx'\n"
.section .bss
    .lcomm buffer, 12
.section .text
.code32
.globl _start
_start:
    movl $0, %eax
    cpuid
    movl $output, %edi

在 .bss 部分我定义了一个名为“buffer”的变量

当我尝试在 gdb 中获取其地址/值时,它只会打印:

(gdb) p $缓冲区 $1 = 无效

使用objdump,发现ELF文件中没有名字,那么在as和ld运行时如何保留这些名字信息呢?谢谢!

【问题讨论】:

  • 如何组装源文件?你使用什么命令和选项?
  • 我试过as -g -gstabs -gstabs+ -gdwarf-2 -ams选项,可以在*.o文件中生成符号名,但是在ld之后这个信息就丢失了。
  • 你使用了什么ld 命令?此外,您在as 命令行上忘记了--32。因此,您正在创建一个包含 32 位机器代码的 64 位目标文件(感谢 .code32 指令)。有关详细信息,请参阅我的答案:P
  • 除非您使用 32 位 Linux 安装,其中 as 和其他所有内容都默认生成 32 位代码。顺便说一句,这段代码的汇编和运行与 64 位相同,但 IDK 你在它之后所拥有的。

标签: assembly gdb elf debug-symbols gnu-assembler


【解决方案1】:

使用 objdump 发现名字不在 ELF 文件中

在带有 GNU binutils 2.28.0-3 的 Arch Linux 上为我工作。也许你在链接后剥离了你的二进制文件?

$ gcc -Wall -m32 -nostdlib gas-symbols.S
$ file a.out
a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, BuildID[sha1]=d5fdff41cc52e9de3b4cdae34cf4129de2b4a69f, not stripped

$ nm a.out 
080490ee B __bss_start
080490f0 b buffer           ### local symbol in the bss
080490ee D _edata
080490fc B _end
080490c4 d output
080480b8 T _start

我不需要-g 来保留可执行文件中的符号。而且,在我的系统上,-static-nostdlib 的默认值。情况并非总是如此,请参阅 this Q&A 关于将 asm 源代码构建为 32 或 64 位静态或动态二进制文件,使用 gcc 或直接使用 asld。或者使用 NASM 和 ld

(请注意.code32 不会更改目标文件格式。您需要使用构建选项,因此最好省略.code32,这样您更有可能得到错误(例如来自push %ebx)如果您尝试将 32 位代码构建到 64 位目标文件中。)

直接使用asld(gcc 在后台使用,使用gcc -v 看看如何),我也得到了相同的结果。

$ as gas-symbols.S -o gas-symbols.o  --32 && 
  ld -o a.out gas-symbols.o  -m elf_i386
$ nm a.out 
...
080490b0 b buffer        ## Still there
...

在 GDB 中,正如 Jester 指出的那样,打印地址而不是值。 GDB 不知道它是一个数组,因为您没有使用任何指令来创建调试信息。 (我不建议尝试手动编写此类指令。例如,查看 gcc -Sstatic char foo[100]; 发出的内容(在文件中)。

无论如何,如果你使用得当,GDB 就可以工作:

$ gdb ./a.out
(gdb) b _start
(gdb) r
Starting program: /home/peter/src/SO/a.out

Breakpoint 1, _start () at gas-symbols.S:10
(gdb) p buffer
$1 = 0
(gdb) p &buffer
$2 = (<data variable, no debug info> *) 0x80490f0 <buffer>
(gdb) ptype buffer
type = <data variable, no debug info>

您可以通过强制转换或使用x 命令来解决缺少类型信息的问题

(gdb) p (char[12])buffer
$4 = '\000' <repeats 11 times>
(gdb) p /x (char[12])buffer
$5 = {0x0 <repeats 12 times>}
(gdb) x /4w &buffer             # eXamine the memory as 4 "words" (32-bit).  
0x80490f0 <buffer>:     0x00000000      0x00000000      0x00000000      0x00000000
(gdb) help x   # read this to learn about options for dumping memory

对于调试 asm,我的 ~/.gdbinit 中有这个:

set disassembly-flavor intel
layout reg
set print static-members off

但由于您使用 AT&T 语法编写,您可能不想要 intel 风格的反汇编。不过,layout asm / layout reg 很棒。另请参阅 标签 wiki 末尾的调试提示。标签 wiki 充满了文档和指南的链接。

【讨论】:

  • 现在我很清楚了:)。谢谢你的详细解答!
  • @Yichen:您应该将其中一个答案标记为“已接受”(上/下投票箭头下方的复选框)
【解决方案2】:

您应该使用p &amp;buffer 而不是p $buffer$ 是立即操作数的汇编语法,而在 gdb 中则是便利变量(和寄存器)前缀。要打印内容,请使用 x/12c &amp;bufferp (char[12])buffer

PS:调试信息也适用于本地,你不需要它是全局的。

【讨论】:

    【解决方案3】:

    .lcomm 定义了一个本地通用符号。公共符号只存在于目标文件中,不存在于可执行文件中,因此ld 看不到它们。

    如果您想要一个对ld 可见的符号,则应将其设为.global(或.globl,具体取决于您的汇编程序)。

    通用符号的想法是允许您在多个编译单元中定义相同的符号。链接后它们就消失了。

    【讨论】:

    • 谢谢。我想没有名称信息有点不方便。您是否认为在 as-ld-gdb 工具链中不可能支持它,或者只是没有人尝试过这样做?毕竟,在 C 代码中,函数可以使用同名的局部变量,gdb 可以根据上下文区分它们。
    • 这不是限制,而是设计使然。这些有点像 C 中的 extern 声明。我不知道您为什么希望这些在链接后可用。对我来说听起来像an X-Y problem。你实际上想用这些符号做什么?
    • 我想知道如果程序员通过.lcomm声明符号并试图在gdb中获取它们的地址并跟踪它们的值,他应该怎么做?
    • 那些符号在发生链接后没有值,因为那些符号不再存在了。
    • @CodyGray:实际上,除非您告诉链接器剥离二进制文件(ld --strip-debug--strip-all),否则目标文件中的符号仍然存在于可执行文件的符号表中默认。
    猜你喜欢
    • 1970-01-01
    • 2015-03-10
    • 2013-09-03
    • 1970-01-01
    • 1970-01-01
    • 2015-11-24
    • 2016-02-29
    • 1970-01-01
    • 2017-03-11
    相关资源
    最近更新 更多