从内联汇编跳转到C的标签

问题描述 投票:0回答:1

我在汇编中有一段书面代码,在某些时候,我想跳到C中的标签。所以我有以下代码(简化版,但仍然有同样的问题):

    #include <stdio.h>

    #define JE asm volatile("jmp end");
    int main(){
        printf("hi\n");
        JE
        printf("Invisible\n");
        end:
        printf("Visible\n");
        return 0;
    }

此代码已编译,但反汇编版本中没有end标签。

如果我将标签名称从end更改为其他任何东西(比如说l1,无论是在asm代码(jmp l1)中还是在C代码中,编译器都会说

    main.c:(.text+0x6b): undefined reference to `l1'
    collect2: error: ld returned 1 exit status
    Makefile:2: recipe for target 'main' failed
    make: *** [main] Error 1

我尝试了不同的操作(不同的长度,不同的大小写,上,下等),我认为它只能使用end标签进行编译。使用end标签,我收到分段错误,因为在反汇编版本中没有end标签。

编译: gcc -O0 main.c -o main

反汇编代码:

    000000000000063a <main>:
     63a:   55                      push   %rbp
     63b:   48 89 e5                mov    %rsp,%rbp
     63e:   48 8d 3d af 00 00 00    lea    0xaf(%rip),%rdi        # 6f4 <_IO_stdin_used+0x4>
     645:   e8 c6 fe ff ff          callq  510 <puts@plt>
     64a:   e9 c9 09 20 00          jmpq   201018 <_end> # there is no _end label!
     64f:   48 8d 3d a1 00 00 00    lea    0xa1(%rip),%rdi        # 6f7 <_IO_stdin_used+0x7>
     656:   e8 b5 fe ff ff          callq  510 <puts@plt>
     65b:   48 8d 3d 9f 00 00 00    lea    0x9f(%rip),%rdi        # 701 <_IO_stdin_used+0x11>
     662:   e8 a9 fe ff ff          callq  510 <puts@plt>
     667:   b8 00 00 00 00          mov    $0x0,%eax
     66c:   5d                      pop    %rbp
     66d:   c3                      retq   
     66e:   66 90                   xchg   %ax,%ax

所以,问题是:

  1. 我做错什么了吗?我已经看到这种跳跃(从代码中的C)。我可以提供示例链接。
  2. 为什么编译器/链接器找不到l1但可以找到end
c gcc x86 inline-assembly goto
1个回答
2
投票

这就是asm goto的作用。 GCC Inline Assembly: Jump to label outside block

请注意,定义标签inside另一个asm语句有时会起作用(例如,禁用优化),但并不安全。

    asm("end:");   // BROKEN; NEVER USE 
                   // except for toy experiments to look at compiler output

[GNU C没有定义没有asm goto的情况下从一个asm语句跳转到另一asm语句的行为。允许编译器假定执行是在asm语句的末尾执行的,例如在它后面放一个商店。


给定函数中的C end:标签不会仅具有end_end:的asm符号名称-这没有意义,因为每个单独的C函数都允许具有各自的C函数拥有end:标签。 可能类似于main.end,但事实证明,GCC和clang仅使用其通常的自动编号标签,例如.L123

然后此代码的工作方式:https://github.com/IAIK/transientfail/blob/master/pocs/spectre/PHT/sa_oop/main.c

不会; end引用的asm volatile("je end");标签在.data部分中,并且碰巧是由编译器或链接器定义的,以标记该部分的结尾

[asm volatile("je end")与该功能中的C标签无关。

我注释掉了其他函数中的某些代码,以使其在没有“ cacheutils.h”标头的情况下进行编译,但这并不影响oop()函数的那部分;有关将JE_4k更改为JE_16的链接可执行文件的反汇编,请参见https://godbolt.org/z/jabYu3,因此它并不大。它是对链接的可执行文件的分解,因此您可以看到je 6010f0 <_end>的数字地址,而oop函数本身的起始地址为4006e0,结束于400750。(因此,它不包含分支目标)。

如果这恰好适用于Spectre漏洞,那是因为显然该分支从未被实际采用。

© www.soinside.com 2019 - 2024. All rights reserved.