在尝试优化x86_64上的返回值时,我注意到一件奇怪的事情.即,给出代码:
#include <cstdint>
#include <tuple>
#include <utility>
using namespace std;
constexpr uint64_t a = 1u;
constexpr uint64_t b = 2u;
pair<uint64_t, uint64_t> f() { return {a, b}; }
tuple<uint64_t, uint64_t> g() { return tuple<uint64_t, uint64_t>{a, b}; }
Run Code Online (Sandbox Code Playgroud)
Clang 3.8输出此汇编代码f:
movl $1, %eax
movl $2, %edx
retq
Run Code Online (Sandbox Code Playgroud)
这个用于g:
movl $2, %eax
movl $1, %edx
retq
Run Code Online (Sandbox Code Playgroud)
哪个看起来最佳.但是,使用GCC 6.1编译时,生成的程序集f与Clang输出相同,生成的程序集为g:
movq %rdi, %rax
movq $2, (%rdi)
movq $1, 8(%rdi)
ret
Run Code Online (Sandbox Code Playgroud)
看起来返回值的类型被GCC归类为MEMORY,而Clang归类为INTEGER.我可以确认将Clang代码与GCC代码链接这样的代码可能会导致分段错误(Clang调用GCC编译 …
我正处于一个项目的设计阶段,该项目需要执行大量简单的 256 位整数运算(仅加、子、多、分),并且需要针对这四个操作进行合理优化的东西。
我已经熟悉 GMP、NTL 和大多数其他重量级 bignum 实现。然而,这些实现的开销促使我做我自己的低级实现——我真的不想这样做;众所周知,这东西很难做对。
在我的研究中,我注意到 Clang 中新的扩展整数类型 - 我是 gcc 用户 - 我想知道是否有人对现实生活中的扩展整数有任何经验,愤怒的实现?它们是否针对“明显的”位大小(256、512 等)进行了优化?
我在 linux 下的 x-64 上使用 C 语言(目前是 Ubuntu,但如果需要,可以向其他发行版开放)。我主要使用 gcc 进行生产工作。
编辑添加:@phuclv 确定了以前的答案C++ 128/256-bit fixed size integer types。(感谢@phuclv。)这个q/a 侧重于c++ 支持;我希望确定是否有人对新的 Clang 类型有任何特定的经验。
考虑以下几乎叶函数:
int almost_leaf(int* x) {
if (__builtin_expect(*x >= 0, true)) {
return *x;
}
return x_was_negative() + 1;
}
Run Code Online (Sandbox Code Playgroud)
它几乎是叶子,因为它不是严格意义上的叶子函数(它可能调用x_was_negativeis x 为负数,但__builtin_expect提示编译器return *x通常采用分支,这不涉及任何调用。
clang-16 像这样编译它:
almost_leaf(int*): # @almost_leaf(int*)
push rax
mov eax, dword ptr [rdi]
test eax, eax
js .LBB0_1
pop rcx
ret
.LBB0_1:
call x_was_negative()
inc eax
pop rcx
ret
Run Code Online (Sandbox Code Playgroud)
快速(预期)路径上的and (直到第一个的部分)在这里push是完全不必要的:堆栈未使用,并且不会进行需要“由于 ABI”而对齐的堆栈的调用。popret
最好将堆栈对齐到x_was_negative()调用的慢速路径上,就像 gcc 那样:
almost_leaf(int*):
mov eax, DWORD PTR [rdi] …Run Code Online (Sandbox Code Playgroud) 我经常听说使用神灵语言汇编语言编写的应用程序.我从来没有尝试过,我甚至都不知道该怎么做.
如果我想涉猎,我该怎么做呢?我完全不知道需要什么,虽然可能是某种编译器和记事本.
纯粹出于好奇,我需要写一个"Hello World!" 应用?
编辑添加,我正在运行Windows 7 64位
编辑添加,我想知道是否有Visual Studio的汇编语言插件?
我正在为64位x86生成以下指令:
41 F3 0F 10 46 10 movss XMM0,014h[R14]
Run Code Online (Sandbox Code Playgroud)
不幸的是,它在该行上出现故障.gdb将其反汇编为:
0x0000000000402054 <+320>: rex.B
0x0000000000402055 <+321>: movss 0x14(%rsi),%xmm0
Run Code Online (Sandbox Code Playgroud)
请注意,无法识别rex.B覆盖,索引是RSI而不是R14.
指令无效吗?在AMD 64位指令参考中,我找不到任何迹象表明此编码无效.
objdump也无法将其识别为有效指令:
41 rex.B
f3 0f 10 46 10 movss 0x10(%rsi),%xmm0
Run Code Online (Sandbox Code Playgroud)
这里发生了什么?
我正在尝试学习x86_64程序集,我今天正在尝试标准输入输出并偶然发现这个帖子学习程序集 - echo程序名称如何从STDIN读取输入(使用SYSCALL指令)?特别是如果我知道输入将始终是一个整数,我想将其读入寄存器?
编辑: @Daniel Kozar在下面的回答帮助我理解了STDIN和STDOUT如何与Linux上的SYSCALL指令一起工作.我试图编写一个小程序,它从控制台输入中读取一个数字并打印与该数字对应的ascii字符.假如你输入65作为输入,你应该得到A作为输出.还有一个新的线条角色.如果有的话,它可以帮助任何其他人:-)
section .text
global _start
_start:
mov rdi, 0x0 ; file descriptor = stdin = 0
lea rsi, [rsp+8] ; buffer = address to store the bytes read
mov rdx, 0x2 ; number of bytes to read
mov rax, 0x0 ; SYSCALL number for reading from STDIN
syscall ; make the syscall
xor rax, rax ; clear off rax
mov rbx, [rsp+8] ; read the first byte read into rsp+8 by STDIN call …Run Code Online (Sandbox Code Playgroud) 考虑以下简单程序:
int main(int argc, char **argv)
{
char buffer[256];
buffer[0] = 0x41;
buffer[128] = 0x41;
buffer[255] = 0x41;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在x86-64机器上使用GCC 4.7.0编译.用GDB反汇编main()给出:
0x00000000004004cc <+0>: push rbp
0x00000000004004cd <+1>: mov rbp,rsp
0x00000000004004d0 <+4>: sub rsp,0x98
0x00000000004004d7 <+11>: mov DWORD PTR [rbp-0x104],edi
0x00000000004004dd <+17>: mov QWORD PTR [rbp-0x110],rsi
0x00000000004004e4 <+24>: mov BYTE PTR [rbp-0x100],0x41
0x00000000004004eb <+31>: mov BYTE PTR [rbp-0x80],0x41
0x00000000004004ef <+35>: mov BYTE PTR [rbp-0x1],0x41
0x00000000004004f3 <+39>: mov eax,0x0
0x00000000004004f8 <+44>: leave
0x00000000004004f9 <+45>: ret
Run Code Online (Sandbox Code Playgroud)
当缓冲区为256字节时,为什么sub rsp只有0x98 = 152d?当我将数据移入缓冲区[0]时,它似乎只是使用分配的堆栈帧之外的数据并使用rbp来引用,那么甚至sub rsp的点是什么,0x98? …
我一直在使用Java一段时间,而我设置新开发机器的典型仪式需要从Oracle网站下载和安装最新JDK的规范.
这引发了一个不寻常的问题, does it matter if I use the 32bit or 64bit JRE bundle?
回过头来看,我之前已经安装了两个版本,而且我的普通工具链很快就插入了(Eclipse).在我的日常编程中,我不记得曾经因为我使用的是64位JRE(或针对这方面的目标是64位JRE)而不得不以不同的方式改变某些东西或思考某些东西.
根据我对64位与32位的理解 - 它实际上归结为数字如何存储在封面下...我知道这int是32位并且long是64位...与float32位相同并且double是64位 - 所以只是Java已经抽象出了这个微妙之处,并且可能一直都是"64位兼容"吗?
我确定我在这里遗漏了一些东西,除了无法在32位系统上安装64位JRE.
以下汇编代码as在OSX 10.9.4上运行时出错,但在Linux(Debian 7.6)上成功运行.特别是,movq指令似乎不喜欢label参数.
$ cat test.S
.globl _main
_main:
movq $_main, %rax
ret
Run Code Online (Sandbox Code Playgroud)
这是错误:
$ as -o test.o test.S
test.S:3:32-bit absolute addressing is not supported for x86-64
test.S:3:cannot do signed 4 byte relocation
Run Code Online (Sandbox Code Playgroud)
将$_main第3行更改为文字$10就好了.
代码必须以非常小的方式进行修改才能在Linux上运行 - 只需从标签中删除下划线即可.
$ cat test.S
.globl main
main:
movq $main, %rax
ret
Run Code Online (Sandbox Code Playgroud)
很容易独立验证代码在Linux上是否可行:
$ as -o test.o test.S
$ gcc -o test.out test.o
$ ./test.out
Run Code Online (Sandbox Code Playgroud)
请忽略代码并没有真正做很多事情,我故意尽可能地将其修剪下来以证明错误.
我已经看了很多使用LEA(加载有效地址),但在我做出改变之前,我想了解其中的区别 - 为什么它适用于Linux而不是OSX?
我试图在nasm中创建一个应该显示该字母的简单程序a.然而,它给了我一个Segfault并说:
./a.out: Symbol `printf' causes overflow in R_X86_64_PC32 relocation
Segmentation fault (core dumped)
Run Code Online (Sandbox Code Playgroud)
基本上,我试图将值0x61(字母a的十六进制)移动到内存地址1234,然后将其作为参数传递给printf.这是我的确切代码:
extern printf
section .text
global main
main:
push rbp
mov rax,0
mov qword [1234], 0x61 ; move 0x61 into address 1234
mov rdi, qword [1234] ; mov address 1234 into rdi
call printf ; should print the letter a
pop rbp
mov rax,0
ret
Run Code Online (Sandbox Code Playgroud)
我正在运行Linux x86_64