我一直在阅读div和mul组装操作,我决定通过在C中编写一个简单的程序来实现它们:
#include <stdlib.h>
#include <stdio.h>
int main()
{
size_t i = 9;
size_t j = i / 5;
printf("%zu\n",j);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
然后生成汇编语言代码:
gcc -S division.c -O0 -masm=intel
Run Code Online (Sandbox Code Playgroud)
但是看生成的division.s文件,它不包含任何div操作!相反,它通过位移和魔术数字来做某种黑魔法.这是一个计算代码片段i/5:
mov rax, QWORD PTR [rbp-16] ; Move i (=9) to RAX
movabs rdx, -3689348814741910323 ; Move some magic number to RDX (?)
mul rdx ; Multiply 9 by magic number
mov rax, rdx ; Take only the upper 64 bits of the …Run Code Online (Sandbox Code Playgroud) 我想检查boost::variant在我的代码中应用的程序集输出,以便查看哪些中间调用被优化掉了.
当我编译以下示例(使用GCC 5.3 g++ -O3 -std=c++14 -S)时,似乎编译器优化了所有内容并直接返回100:
(...)
main:
.LFB9320:
.cfi_startproc
movl $100, %eax
ret
.cfi_endproc
(...)
Run Code Online (Sandbox Code Playgroud)
#include <boost/variant.hpp>
struct Foo
{
int get() { return 100; }
};
struct Bar
{
int get() { return 999; }
};
using Variant = boost::variant<Foo, Bar>;
int run(Variant v)
{
return boost::apply_visitor([](auto& x){return x.get();}, v);
}
int main()
{
Foo f;
return run(f);
}
Run Code Online (Sandbox Code Playgroud)
但是,完整的程序集输出包含的内容远远超过上面的摘录,对我而言,它看起来永远不会被调用.有没有办法告诉GCC/clang删除所有"噪音"并输出程序运行时实际调用的内容?
完整装配输出:
.file "main1.cpp"
.section .rodata.str1.8,"aMS",@progbits,1
.align 8
.LC0:
.string "/opt/boost/include/boost/variant/detail/forced_return.hpp"
.section .rodata.str1.1,"aMS",@progbits,1
.LC1: …Run Code Online (Sandbox Code Playgroud) 我正在阅读“计算机系统:程序员的视角,3/E”(CS:APP3e),以下代码是书中的示例:
long call_proc() {
long x1 = 1;
int x2 = 2;
short x3 = 3;
char x4 = 4;
proc(x1, &x1, x2, &x2, x3, &x3, x4, &x4);
return (x1+x2)*(x3-x4);
}
Run Code Online (Sandbox Code Playgroud)
书中给出了GCC生成的汇编代码:
long call_proc()
call_proc:
; Set up arguments to proc
subq $32, %rsp ; Allocate 32-byte stack frame
movq $1, 24(%rsp) ; Store 1 in &x1
movl $2, 20(%rsp) ; Store 2 in &x2
movw $3, 18(%rsp) ; Store 3 in &x3
movb $4, 17(%rsp) ; Store 4 in …Run Code Online (Sandbox Code Playgroud) 我正在阅读计算机系统:程序员的观点,家庭作业是描述这种算法是如何工作的.
C功能:
void store_prod(__int128 *dest, int64_t x, int64_t y) {
*dest = x * (__int128)y;
}
Run Code Online (Sandbox Code Playgroud)
部件:
movq %rdx, %rax
cqto
movq %rsi, %rcx
sarq $63, %rcx
imulq %rax, %rcx
imulq %rsi, %rdx
addq %rdx, %rcx
mulq %rsi
addq %rcx, %rdx
movq %rax, (%rdi)
movq %rdx, 8(%rdi)
ret
Run Code Online (Sandbox Code Playgroud)
我不知道它为什么表现: xh * yl + yh * xl = value which we add after unsigned multiplication
我今天进行了测试,我唯一不理解的问题是将双字转换为四字.
这让我思考,为什么/我们什么时候签署扩展乘法或除法?另外,我们何时使用像cdq这样的指令?
我的大学给了我一个练习:
1.在Jasmin中创建一个新文档
2. 使用 AL 寄存器将 9 加到 8。
3. 减去 2。
4. 除以 7。
我的解决方案是:
mov al,9
add al,8
sub al,2
Run Code Online (Sandbox Code Playgroud)
但如何除以 7 呢?我尝试过类似的方法,div al,7但这不起作用。
当将x设置为零(x = 0)时,我的csapp书指出了两种方法。
第一:
xorq %rcx, %rcx
Run Code Online (Sandbox Code Playgroud)
第二:
movq $0, %rcx
Run Code Online (Sandbox Code Playgroud)
它还表明第一个仅占用3个字节,而第二个仅占用7个字节。
两种方式如何运作?为什么第一个字节比第二个字节少?
我注意到EDX包含一些随机默认值,如00401000,然后我使用这样的DIV指令:
mov eax,10
mov ebx,5
div ebx
Run Code Online (Sandbox Code Playgroud)
它会导致INTEGER OVERFLOW ERROR.但是,如果我设置edx为0并执行相同的操作.我相信使用div会导致商重写eax和其余覆盖edx.
获得此INTEGER OVERFLOW ERROR确实让我感到困惑.
我正在阅读这本教科书,Randal E. Bryant、David R. O\xe2\x80\x99Hallaron - 计算机系统。A Programmer\xe2\x80\x99s Perspective [3rd ed.] (2016, Pearson)
\n我一直在弄清楚作者如何计算出开关表的案例编号,如下所示~
我不确定的是他们如何获得案例编号,例如Case Ais Case 5: 以及如何Case 2/7isCase C和Case D,对于本示例中的其余案例,依此类推
任何帮助表示感谢,谢谢!!
\n\n\n\nassembly ×9
x86 ×5
x86-64 ×5
c ×4
gcc ×3
128-bit ×1
c++ ×1
clang ×1
code-size ×1
jump-table ×1
machine-code ×1
stack-memory ×1