简体   繁体   English

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

[英]Jump to a label from inline assembly to C

I have a written piece of code in assembly and at some points of it, I want to jump to a label in C .我在汇编中有一段编写好的代码,在某些方面,我想跳转到C的标签。 So I have the following code (shortened version but still, I am having the same problem):所以我有以下代码(缩短版本,但我仍然遇到同样的问题):

    #include <stdio.h>

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

This code compiles, but there is no end label in the disassembled version of the code.这段代码可以编译,但在反汇编版本的代码中没有end标签。

If I change the label name from end to any other thing (let's say l1 , both in asm code( jmp l1 ) and in the C code), the compiler says that如果我将标签名称从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

I have tried different things(different length, different cases, upper, lower, etc.) and I think it only compiles with end label.我尝试了不同的东西(不同的长度、不同的情况、上、下等),我认为它只能用end标签编译。 And with end label, I am receiving segmentation fault because, there is no end label in the disassembled version.对于end标签,我收到分段错误,因为反汇编版本中没有end标签。

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

Disassembled code:反汇编代码:

    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

So, the questions are:所以,问题是:

  1. Am I doing something wrong?难道我做错了什么? I have seen this kind of jumps (from assembly to C) in codes.我在代码中看到过这种跳转(从汇编到 C)。 I can provide example links.我可以提供示例链接。
  2. Why the compiler/linker cannot find l1 but can find end ?为什么编译器/链接器找不到l1但可以找到end

This is what asm goto is for.这就是asm goto的用途。 GCC Inline Assembly: Jump to label outside block GCC 内联汇编:跳转到块外的标签

Note that defining a label inside another asm statement will sometimes work (eg with optimization disabled) but IS NOT SAFE.请注意,另一个 asm 语句中定义标签有时会起作用(例如禁用优化)但不安全。

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

GNU C does not define the behaviour of jumping from one asm statement to another without asm goto . GNU C 没有定义从一个 asm 语句asm goto到另一个没有asm goto The compiler is allowed to assume that execution comes out the end of an asm statement and eg put a store after it.允许编译器假设执行出现在asm语句的末尾,例如在它之后放置一个存储。


The C end: label within a given function won't just have the asm symbol name of end or _end: - that wouldn't make sense because separate C functions are each allowed to have their own end: label.给定函数中的 C end:标签不会只有end_end:的 asm 符号名称_end: - 这没有意义,因为每个单独的 C 函数都允许有自己的end:标签。 It could be something like main.end but it turns out GCC and clang just use their usual autonumbered labels like .L123 .可能类似于main.end但事实证明 GCC 和 clang 只是使用他们通常的自动编号标签,如.L123

Then how this code works: https://github.com/IAIK/transientfail/blob/master/pocs/spectre/PHT/sa_oop/main.c那么这段代码是如何工作的: https : //github.com/IAIK/transientfail/blob/master/pocs/spectre/PHT/sa_oop/main.c

It doesn't;它没有; the end label that asm volatile("je end"); asm volatile("je end");end标签asm volatile("je end"); references is in the .data section and happens to be defined by the compiler or linker to mark the end of that section .引用位于.data节中,恰好由编译器或链接器定义以标记该节的结尾

asm volatile("je end") has no connection to the C label in that function. asm volatile("je end")与该函数中的 C 标签没有联系。

I commented out some of the code in other functions to get it to compile without the "cacheutils.h" header but that didn't affect that part of the oop() function;我注释掉了其他函数中的一些代码,让它在没有“cacheutils.h”头的情况下编译,但这并没有影响oop()函数的那部分; see https://godbolt.org/z/jabYu3 for disassembly of the linked executable with JE_4k changed to JE_16 so it's not huge.请参阅https://godbolt.org/z/jabYu3以了解链接的可执行文件的反汇编,其中 JE_4k 更改为 JE_16,因此它不是很大。 It's disassembly of a linked executable so you can see the numeric address of je 6010f0 <_end> while the oop function itself starts at 4006e0 and ends at 400750. (So it doesn't contain the branch target).它是链接可执行文件的反汇编,因此您可以看到je 6010f0 <_end>的数字地址,而oop函数本身从 4006e0 开始并在 400750 结束。(因此它不包含分支目标)。

If this happens to work for Spectre exploits, that's because apparently the branch is never actually taken.如果这恰好适用于 Spectre 漏洞利用,那是因为显然该分支从未真正被采用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM