我试图通过assmbly中的堆栈研究将参数传递给函数.我正在使用Fedora 20,64位系统.
当我尝试以下代码时,
pushl%ebp
popl%ebp
我得到错误,错误:"推"的无效指令后缀
我将如何克服这个错误!
我编译它,如-ggstabs -o Function_Stack.o Function_Stack.c
我搜索并发现我无法__asm在视觉工作室的x64中使用.相反,我必须使用外部程序集文件.
如何将外部程序集文件添加到我的win32控制台项目?
如何编译它们?
你能一步一步解释吗?
考虑这个 C 代码:
void foo(void);
long bar(long x) {
foo();
return x;
}
Run Code Online (Sandbox Code Playgroud)
当我在 GCC 9.3 上使用-O3或编译它时-Os,我得到这个:
bar:
push r12
mov r12, rdi
call foo
mov rax, r12
pop r12
ret
Run Code Online (Sandbox Code Playgroud)
除了选择rbx而不是r12作为被调用者保存的寄存器之外,clang 的输出是相同的。
但是,我希望/期望看到看起来更像这样的程序集:
bar:
push rdi
call foo
pop rax
ret
Run Code Online (Sandbox Code Playgroud)
由于无论如何您都必须将某些内容推送到堆栈中,因此将您的值推送到那里似乎更短,更简单,并且可能更快,而不是将一些任意的被调用者保存的寄存器值推送到那里,然后将您的值存储在该寄存器中。call foo当你把东西放回去后,反之亦然。
我的组装错了吗?它在某种程度上比弄乱额外的寄存器效率低吗?如果这两个的答案都是“否”,那么为什么 GCC 或 clang 不这样做呢?
编辑:这是一个不太简单的例子,即使变量被有意义地使用,它也会发生:
long foo(long);
long bar(long x) {
return foo(x * x) - x;
}
Run Code Online (Sandbox Code Playgroud)
我明白了:
bar:
push rbx …Run Code Online (Sandbox Code Playgroud) 我目前正在尝试了解 x86_64(特别是我的 Intel(R) Core(TM) i3-8145U CPU @ 2.10GHz 处理器)上某些循环的性能属性。具体来说,在循环体内部添加一个额外的读取内存指令几乎可以使性能翻倍,而细节并不是特别重要。
我一直在使用一个测试程序,它由两个主要部分组成:一个测试循环和一个被测函数。测试循环运行被测函数 2 32次,一次将每个有符号的 32 位整数作为参数(按从INT_MIN到 的顺序INT_MAX)。被测函数(名为body)是一个小函数,用于检查是否使用预期参数调用它,否则将错误记录在全局变量中。测试程序涉及的内存量足够小,所有东西都可能适合 L1 缓存。
为了消除可能由编译器行为引起的任何速度差异,我用汇编语言编写了两个有问题的函数(我clang用作汇编程序),并被迫从固定地址(这种测试循环的性能通常受与对齐或缓存相关的影响所支配,因此使用固定地址将消除任何与更改无关的对齐效果或缓存效果)。
这是反汇编的测试循环(它需要函数的地址在 中循环%rdi):
401300: 53 push %rbx
401301: 55 push %rbp
401302: 51 push %rcx
401303: 48 89 fd mov %rdi,%rbp
401306: bb 00 00 00 80 mov $0x80000000,%ebx
loop:
40130b: 89 df mov %ebx,%edi
40130d: ff d5 callq *%rbp
40130f: 83 c3 01 add $0x1,%ebx
401312: 71 f7 jno 40130b <loop> …Run Code Online (Sandbox Code Playgroud) 我发现了一条来自 的评论crossbeam。
从 Intel 的 Sandy Bridge 开始,空间预取器现在一次提取成对的 64 字节缓存线,因此我们必须对齐到 128 字节而不是 64。
资料来源:
我在英特尔的手册中没有找到这样的说法。但直到最新的提交,folly仍然使用 128 字节填充,这让我很有说服力。所以我开始编写代码来看看是否可以观察到这种行为。这是我的代码。
#include <thread>
int counter[1024]{};
void update(int idx) {
for (int j = 0; j < 100000000; j++) ++counter[idx];
}
int main() {
std::thread t1(update, 0);
std::thread t2(update, 1);
std::thread t3(update, 2);
std::thread t4(update, 3);
t1.join();
t2.join();
t3.join();
t4.join();
}
Run Code Online (Sandbox Code Playgroud)
我的CPU是锐龙3700X。当索引为0、1、2、3时,大约需要 1.2 秒才能完成。当索引为0, 16, 32,时 …
我已经通过在C中编写语句,用"gcc -S"编译它们并研究输出,一直在教自己GNU Assembly一段时间.这在x86(并使用-m32编译)上工作正常,但在我的AMD64框中,对于此代码(仅作为示例):
int main()
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
GCC给了我:
.file "test.c" .text .globl main .type main, @function main: .LFB2: pushq %rbp .LCFI0: movq %rsp, %rbp .LCFI1: movl $0, %eax leave ret .LFE2: .size main, .-main .section .eh_frame,"a",@progbits .Lframe1: .long .LECIE1-.LSCIE1 .LSCIE1: .long 0x0 .byte 0x1 .string "zR" .uleb128 0x1 .sleb128 -8 .byte 0x10 .uleb128 0x1 .byte 0x3 .byte 0xc .uleb128 0x7 .uleb128 0x8 .byte 0x90 .uleb128 0x1 .align 8 .LECIE1: .LSFDE1: .long .LEFDE1-.LASFDE1 .LASFDE1: .long .LASFDE1-.Lframe1 .long .LFB2 .long …
在执行该指令之前,fs包含0x0.
另外我想知道如何从GDB中的这个内存区读取,这个命令是什么?
该在线LLVM演示页面有一个选项生成LLVM C++ API代码从一个源代码后端.但是,该演示页面现已禁用.我想知道我们如何使用可用的LLVM工具自己完成它.
我尝试了以下内容
clang++ -c -emit-llvm input.cpp -o input.ll
llc -march=cpp -o input.ll.cpp input.ll
Run Code Online (Sandbox Code Playgroud)
这给出了以下错误
llc: error: invalid target 'cpp'.
Run Code Online (Sandbox Code Playgroud)
我使用的是LLVM/Clang 3.2版.
我在下面的x86_64非常复杂的程序上做了gcc -S:
int main() {
int x = 3;
x = 5;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
而我得到的是:
.file "main.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $3, -4(%rbp)
movl $5, -4(%rbp)
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-3)"
.section .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)
我想知道是否有人可以帮助我理解输出或引用我的一些链接解释.具体来说,cfi ,LFB0,LFE0 , leave意味着什么?关于这些我能找到的就是这篇文章但却无法完全理解它的用途.另外,ret在这种情况下做什么?我猜它正在回归__libc_start_main(),反过来会打电话 …
我试图使用64位积分作为位图,并原子地获取/释放各个位的所有权.
为此,我编写了以下无锁代码:
#include <cstdint>
#include <atomic>
static constexpr std::uint64_t NO_INDEX = ~std::uint64_t(0);
class AtomicBitMap {
public:
static constexpr std::uint64_t occupied() noexcept {
return ~std::uint64_t(0);
}
std::uint64_t acquire() noexcept {
while (true) {
auto map = mData.load(std::memory_order_relaxed);
if (map == occupied()) {
return NO_INDEX;
}
std::uint64_t index = __builtin_ctzl(~map);
auto previous =
mData.fetch_or(bit(index), std::memory_order_relaxed);
if ((previous & bit(index)) == 0) {
return index;
}
}
}
private:
static constexpr std::uint64_t bit(std::uint64_t index) noexcept {
return std::uint64_t(1) << index;
}
std::atomic_uint64_t mData{ …Run Code Online (Sandbox Code Playgroud)