【问题标题】:gcc - structures as label for debugginggcc - 作为调试标签的结构
【发布时间】:2016-01-29 08:57:34
【问题描述】:

上下文:

Linux 64.

我想告诉 gcc 在使用 gcc -O0 -S -g myprog.c 生成程序集时保持结构不变

我的意思是:我不希望通过地址引用结构,而是希望它们被标签引用。这将简化解析而无需再次阅读源代码。

所以,例如:

struct mystruct{
    int32_t a;
    char * b;
}

会变成这样:

label_mystruct:
    -4(label_mystruct)
    -12(label_mystruct)

例如,被引用:

add $56, -4(label_mystruct)

目前是这样引用的

.globl _main
_main:
LFB13:
LM157:
    pushq %rbp  #
LCFI27:
    movq %rsp, %rbp#,
LCFI28:
    subq $80, %rsp#,
    movl %edi,-68(%rbp) # argc, argc,
    movq %rsi,-80(%rbp) # argv, argv

    Next line is the culprit:
    movq -56(%rbp), %rdx # list, D.3781
    movq -16(%rbp), %rax # arr, D.3780
    movq %rdx, %rsi # D.3781,
    movq %rax, %rdi # D.3780,
    call _myaddhu   #

我希望它是

label_mystruct:
    -4(label_mystruct)
    -12(label_mystruct)

.globl _main
_main:
LFB13:
LM157:
    pushq %rbp  #
LCFI27:
    movq %rsp, %rbp#,
LCFI28:
    subq $80, %rsp#,
    movl %edi,-68(%rbp) # argc, argc,
    movq %rsi,-80(%rbp) # argv, argv

    Now it is fine:
    movq label_mystruct, %rdx # list, D.3781
    movq -16(%rbp), %rax # arr, D.3780
    movq %rdx, %rsi # D.3781,
    movq %rax, %rdi # D.3780,
    call _myaddhu   #

问题:

在不使用外部工具的情况下,使用 gcc 是否可行?

【问题讨论】:

  • “保持结构不变”是什么意思?顺序保证是相同的(位域有一些例外,AFAIK)。你指的是填充吗?
  • 我的问题是我丢失了结构定义方式的信息。解析时,我希望能够知道我在结构中的位置,而无需再次阅读源代码。我刚刚编辑了问题。
  • “我在哪里”是什么意思?你是怎么解析的?你必须具体,否则这将是一个 XY-problem 没人会解决。
  • 更新了问题 ;)

标签: c gcc assembly


【解决方案1】:

我认为这是不可能的,这是 GCC 中使用的设置。

这里的问题是这里的结构存储在堆栈上,你不能真正拥有一个标签来引用堆栈上的东西。如果该结构不在堆栈上,它会有一个引用它的标签(例如,如果它是一个全局变量)。

另一方面,GCC 会生成调试信息,其中包含有关在运行特定代码时放置哪些数据的信息。在您的示例中,它本质上会说“执行此代码时 -56(%ebp) 指向mystruct”。

另一方面,如果您要手动编写汇编代码,您当然可以对变量进行符号引用。例如,您可以这样做:

#define MYSTRUCT -56(%ebp)

...
movq MYSTRUCT, %rdx 

但是MYSTRUCT 将被扩展,并且在汇编代码期间该符号会丢失。如果 GCC 这样做将无济于事(除非-s 生成的汇编代码可能更具可读性),此外 GCC 无论如何都不会通过预处理器传递汇编程序(因为它不这样做)。

【讨论】:

  • 对我来说听起来 OP 想要简单地看到一个结构总是以 [basepointer+fieldoffset] 访问,其中 basepointer 是第一个字段的地址。
  • @MarcovandeVoort:这个。
【解决方案2】:

如果你把你的结构放入静态存储中,你就会明白这一点。这当然会改变代码的含义。比如这段代码

struct {
    int a, b;
} test;

int settest(int a, b) {
    test.a = a;
    test.b = b;
}

编译为(清理):

settest:
    movl    %edi, test(%rip)
    movl    %esi, test+4(%rip)
    ret

    .comm   test,8,4

您也可以尝试将选项 -fverbose-asm 传递给 gcc,它会指示 gcc 添加一些注释,以使程序集更易于阅读。

【讨论】:

  • 我已经这样做了,但它迫使我在“#”之后进行解析。总比没有好,但仍然不理想
  • @Larry 我不认为你可以做得更好,特别是考虑到现代编译器并没有真正为每个变量提供固定地址。
  • 你是对的;即使我已经这样做了,我也会为您提出的解决方案提供积分。 ;)
  • @Larry 如果您觉得这个问题仍然缺乏解决方案,请考虑不要将其标记为已接受,以便其他人知道仍然对不同的方法感兴趣。但是,我相信您找到其他东西的机会非常小。也可以考虑使用 clang。在我看来,它会生成更具可读性的程序集。
  • 我试过clang,但它没有输出更好的程序集来帮助我:(我想我会保留你的答案。我想如果你在你的答案中首先建议fverbose-asm会很棒,因为,它有助于解决问题。它可能是最接近的事情,无需大规模重新设计 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-23
  • 1970-01-01
  • 2022-12-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多