- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
首先:该代码被认为是纯粹的乐趣,请在生产中不要做任何类似的事情。在任何环境下编译并执行这段代码后,对于您,您的公司或您的驯鹿造成的任何伤害,我们概不负责。以下代码不安全,不可移植,并且非常危险。被警告。下面的长帖子。你被警告了。
现在,在免责声明之后:让我们考虑以下代码:
#include <stdio.h>
int fun()
{
return 5;
}
typedef int(*F)(void) ;
int main(int argc, char const *argv[])
{
void *ptr = &&hi;
F f = (F)ptr;
int c = f();
printf("TT: %d\n", c);
if(c == 5) goto bye;
//else goto bye; /* <---- This is the most important line. Pay attention to it */
hi:
c = 5;
asm volatile ("movl $5, %eax");
asm volatile ("retq");
bye:
return 66;
}
fun
,我纯粹是创建该函数作为引用来获取生成的汇编代码。
F
指向不带任何参数并返回一个int的函数。
hi
的地址,这在clang中也适用。然后,我们做一些邪恶的事情,我们创建一个名为f的函数指针
F
并将其初始化为上面的标签。
C
的局部变量,然后我们将其打印出来。
if
,用于检查分配给
c
的值是否实际上是我们需要的值,如果是,请转到
bye
,以便他的应用程序正常退出,退出代码为66。如果可以,则认为这是正常的退出代码。
hi
之后的代码是将5分配给c的值,然后进行两行汇编以将
eax
的值初始化为5并实际从“函数”调用返回。如上所述,有一个引用函数
fun
生成相同的代码。
-O1
,并且
O0
给出相似的结果,尽管更长一些):
# else goto bye is COMMENTED OUT
fun:
mov eax, 5
ret
.LC0:
.string "TT: %d\n"
main:
push rbx
mov eax, OFFSET FLAT:.L3
call rax
mov ebx, eax
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
cmp ebx, 5
je .L4
.L3:
movl $5, %eax
retq
.L4:
mov eax, 66
pop rbx
ret
mov eax, OFFSET FLAT:.L3
,其中
L3
对应于我们的
hi
标签,其后一行:实际调用它的
call rax
。
ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 66
TT: 5
-O0
,我们得到由gcc生成的以下程序集:
# else goto bye is UNCOMMENTED
# even gcc -O0 "knows" hi: is unreachable.
fun:
push rbp
mov rbp, rsp
mov eax, 5
pop rbp
ret
.LC0:
.string "TT: %d\n"
main:
push rbp
mov rbp, rsp
sub rsp, 48
mov DWORD PTR [rbp-36], edi
mov QWORD PTR [rbp-48], rsi
mov QWORD PTR [rbp-8], OFFSET FLAT:.L4
mov rax, QWORD PTR [rbp-8]
mov QWORD PTR [rbp-16], rax
mov rax, QWORD PTR [rbp-16]
call rax
mov DWORD PTR [rbp-20], eax
mov eax, DWORD PTR [rbp-20]
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
cmp DWORD PTR [rbp-20], 5
nop
.L4:
mov eax, 66
leave
ret
ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 66
printf
,而罪魁祸首是
mov QWORD PTR [rbp-8], OFFSET FLAT:.L4
行,其中
L4
实际上对应于我们的
bye
标签。
hi
添加到生成的代码中之后,该部分中没有一段代码。
c
与5进行比较的代码。
O0
的clang会产生以下噩梦,这种噩梦会崩溃:
# else goto bye is UNCOMMENTED
# clang -O0 also doesn't emit any instructions for the hi: block
fun: # @fun
push rbp
mov rbp, rsp
mov eax, 5
pop rbp
ret
main: # @main
push rbp
mov rbp, rsp
sub rsp, 48
mov dword ptr [rbp - 4], 0
mov dword ptr [rbp - 8], edi
mov qword ptr [rbp - 16], rsi
mov qword ptr [rbp - 24], 1
mov rax, qword ptr [rbp - 24]
mov qword ptr [rbp - 32], rax
call qword ptr [rbp - 32]
mov dword ptr [rbp - 36], eax
mov esi, dword ptr [rbp - 36]
movabs rdi, offset .L.str
mov al, 0
call printf
cmp dword ptr [rbp - 36], 5
jne .LBB1_2
jmp .LBB1_3
.LBB1_2:
jmp .LBB1_3
.LBB1_3:
mov eax, 66
add rsp, 48
pop rbp
ret
.L.str:
.asciz "TT: %d\n"
O1
,我们将从gcc获得:
# else goto bye is UNCOMMENTED
# gcc -O1
fun:
mov eax, 5
ret
.LC0:
.string "TT: %d\n"
main:
sub rsp, 8
mov eax, OFFSET FLAT:.L3
call rax
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
.L3:
mov eax, 66
add rsp, 8
ret
hi
部分(
mov eax, OFFSET FLAT:.L3
脚尖移到
L3
,它对应于我们的
bye
部分),不幸的是,决定在
rsp
之前增加
ret
是一个好主意,以便确保我们在需要的地方完全不同成为。
# else goto bye is UNCOMMENTED
# clang -O1
fun: # @fun
mov eax, 5
ret
main: # @main
push rax
mov eax, 1
call rax
mov edi, offset .L.str
mov esi, eax
xor eax, eax
call printf
mov eax, 66
pop rcx
ret
.L.str:
.asciz "TT: %d\n"
1
? c到底是怎么结束的呢?
if
之后将
if
和
else
都移到同一位置的死代码,但是在这里我的知识和见识就停止了。
else
分支,编译器便决定将这两个标签视为等效,或者为什么clang在其中添加了1,最后但并非最不重要:对C标准有深刻理解的人可能会指出这段代码与正常情况的偏差如此之大,以至于我们最终陷入了这种非常奇怪的情况。
最佳答案
someone with a deep understanding of the C standard could maybe point out where this piece of code deviated so badly from normality that we ended up in this really really weird situation.
goto
标签也是UB。
asm
语句在此处发出
ret
指令来使此工作生效。
if(0) { ... }
不发出任何实现
...
的指令
c=5
中的
hi:
编译时完全禁用了优化(并且
else goto bye
注释了),类似于
movl $5, -20(%rbp)
的asm。即使用调用者的RBP修改调用者堆栈框架中的局部变量。因此,您有一个嵌套函数。
mov
-immediate存储到堆栈的机器代码的可执行蹦床,如果您使用指向嵌套函数的指针!)
asm volatile ("movl $5, %eax");
缺少EAX上的垃圾。如果正常到达此语句,则踩到编译器的脚趾,它将是UB,而不是好像它是一个单独的函数。
cli
(禁用中断)之类的指令,没有涉及整数寄存器的任何内容,并且绝对不是
ret
。
asm("")
,也可以将其用作
__attribute__((naked))
函数的主体。
关于c++ - 谜:将GNU C标签指针转换为函数指针,并使用内联asm将ret放入该 block 中。 block 被优化掉了吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59103667/
我试图在 Eclipse v3.7.2 中将 loopj .jar 库添加到我的项目中 首先,我将 .jar 添加到“lib”目录中,右键单击它并选择“添加到构建路径”。它编译得很好,但在执行时出现错
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: Passing two-dimensional array via pointer int table[20
我在 Grafana 中的图表每隔几秒钟就会自动更新一次。随着数据的进入,右侧的最后一个数据点会暂时下降。最终会显示正确的值,但在几次更新时该值较低。这是正常的吗?可以修复吗? 最佳答案 也许,这会有
我不明白为什么我会收到臭名昭著的“IllegalStateException”以及以下代码: private void mergeQueryStrings(String url, Map parame
您好,我正在通过 .php 文件中的 JSON 回显将测试 Android 应用程序链接到 MySQL 数据库。 我能够用整个数据填充 ArrayList,但现在我想将数据分离到变量中,但我无法真正找
我想仅将对象的数据成员的值写入文件,因此这里我不能使用序列化,因为它会写入很多内容其他我不需要的信息。这是我通过两种方式实现的。一种使用字节缓冲区,另一种则不使用它。 不使用 ByteBuffer:第
可能是个简单的问题,但我似乎找不到答案。我正在动态创建一个页面,我可以在其中共享 Twitter 链接。 var twitter = document.createElement('a'); tw
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 9 年前。 Improve
尝试获取我在末尾为 $_SESSION 设置的值作为查询中的 user_id,而不是 $username。我似乎无法修改查询。我确信这对于这里的一些专家来说是非常简单的。 if(isset($_POS
有没有人可以帮助我,我有 mysql 查询,我已经在 phpmyadmin 中测试了它: select items.name, items.category, items.supplier_id, i
我正在尝试 push_back()一个„ std::vector 的符号. 我一直收到错误: character too large for enclosing character literal t
我有一个存储在 char * 中的压缩图像,我想将它放回 AVPacket,以便我可以将它放入 ffmpeg 解码器。有人可以展示如何做到这一点吗?任何示例或教程将不胜感激。 提前致谢 最佳答案 我向
password = str() while password != "changeme": password = input("Password: ") print("Thou Shall
所以我有一个 Map,其中有一些值被传递到一个方法中: public String doThis(Map context){ ..... } 我正在尝试向该 map 插入附加属性 String abc
我遇到了一些我无法弄清楚的问题...我正在编写一个带有接受拖放的 JList 的 Swing Java 应用程序。我想在将文件或文件夹从我的系统拖到 Java 应用程序上时更改光标。 最佳答案 我自己
我正在尝试确定一些关于如何编写异常消息的指南。 例如,让我们假设一个假设的函数必须接收恒定数量的字节(作为 bytes 对象),我们用 [1, 2, 3]。以下是所有可能的异常(exception)情
使用 JSONObject 发送到网络服务当我们将 double(整数)放入零时,该点将被删除 代码 double d = 123.00; JSONObject json = new JSONObje
在 WPF 中,如何将 DataGrid 放在 ComboBox 中以显示多列?像下面这样的东西似乎没有做任何事情:
我正在尝试使用自定义 QStandardItem 在两个 QListViews 之间进行拖放。 除了this document,我在网上找不到我需要的信息这有点帮助,但现在我被困住了。 从一个 QLi
如何将 PDF 放入 NSData 中?我在应用程序的文档目录中以字符串形式找到了 PDF 的位置。当我尝试通过电子邮件发送时,我在电子邮件正文中看到 PDF(而不是看到附件图标。我不知道这是否正常)
我是一名优秀的程序员,十分优秀!