我正在自学一些使用 x86-64 Mac OS 的汇编编程。我试图弄清楚为什么在将正整数除以负整数时会溢出。例如,5/-2必须返回-2。但是,就我而言,它2147483371在我执行时返回 a-554/2而不是-277...这是我的程序集文件中的内容:
; compiling using: nasm -f macho64 -o divide.o divide.s
[bits 64]
global _divide
section .text
; int divide(int dividend, int divisor)
_divide:
xor rdx, rdx ; making this to 0
push rbp ; base stack pointer
mov rax, rdi ; dividend
mov rcx, rsi ; divisor
idiv rcx ; integer division
add rsp, 8
ret
Run Code Online (Sandbox Code Playgroud)
在我的main.c文件中,我有这个:
#include <stdio.h>
extern int divide(int dividend, …Run Code Online (Sandbox Code Playgroud) 我在x86-64汇编中开发了一个程序,该程序需要通过相同的操作进行多次迭代:
IMUL rdx, 3 # rdx is always different
Run Code Online (Sandbox Code Playgroud)
但是,我需要使运行时更快,因此我从上面想到了对该特定行的优化:
MOV rcx, rdx
SHL rdx, 1
ADD rdx, rcx
Run Code Online (Sandbox Code Playgroud)
现在我问你们:这种修改会改善程序的运行时间(减少时钟),还是我应该坚持使用该IMUL命令?
我知道现在很多编译器都非常擅长优化代码。但是,如果一个完全理解现代pc架构的人,是否有可能使代码比编译器更快?比如,如果他用 100% 的汇编编写代码,专注于架构呢?如果它确实有所作为,是否值得?
我一直在阅读有关交换变量内容而不使用临时变量的内容,除了着名的xor算法,我还发现了x86上汇编的XCHG指令.所以我写了这段代码:
void swap(int *left, int *right){
__asm__ __volatile__(
"movl %0, %%eax;"
"movl %1, %%ebx;"
:
: "r" (*left), "r" (*right)
);
__asm__ __volatile__(
"xchg %eax, %ebx;"
);
__asm__ __volatile__(
"movl %%eax, %0;"
"movl %%ebx, %1;"
: "=r" (*left), "=r" (*right)
);}
Run Code Online (Sandbox Code Playgroud)
它确实有效但后来我意识到XCHG指令根本不需要.
void swap(int *left, int *right){
__asm__ __volatile__(
"movl %0, %%eax;"
"movl %1, %%ebx;"
:
: "r" (*left), "r" (*right)
);
__asm__ __volatile__(
"movl %%ebx, %0;"
"movl %%eax, %1;"
: "=r" (*left), "=r" (*right)
);}
Run Code Online (Sandbox Code Playgroud)
第二个函数也可以,但似乎没有人提到使用寄存器交换变量,所以这段代码被认为是错误的,实际上它并没有真正正常工作?我错过了什么吗?
我意识到这只适用于x86,但由于大多数人拥有intel x86处理器,这个代码可以用于任何现实世界的编程吗?我意识到这可能不会比使用临时变量的常规交换更快,但我从理论的角度来问.如果在测试或面试期间有人要求我在C中编写一个函数来交换x86机器的值而不使用临时变量,那么这段代码是有效还是完全废话?谢谢.
我使用内联汇编,我的代码是这样的:
__m128i inl = _mm256_castsi256_si128(in);
__m128i inh = _mm256_extractf128_si256(in, 1);
__m128i outl, outh;
__asm__(
"vmovq %2, %%rax \n\t"
"movzwl %%ax, %%ecx \n\t"
"shr $16, %%rax \n\t"
"movzwl %%ax, %%edx \n\t"
"movzwl s16(%%ecx, %%ecx), %%ecx \n\t"
"movzwl s16(%%edx, %%edx), %%edx \n\t"
"xorw %4, %%cx \n\t"
"xorw %4, %%dx \n\t"
"rolw $7, %%cx \n\t"
"rolw $7, %%dx \n\t"
"movzwl s16(%%ecx, %%ecx), %%ecx \n\t"
"movzwl s16(%%edx, %%edx), %%edx \n\t"
"pxor %0, %0 \n\t"
"vpinsrw $0, %%ecx, %0, %0 \n\t"
"vpinsrw $1, %%edx, %0, …Run Code Online (Sandbox Code Playgroud) 我想尽可能地优化我的函数,我做的一件事就是使用r8作为指针,因为这是指针在x64函数中被推入的寄存器.
但是推送RSI或RDI,将指针移动到它们并在循环中更快地使用它们?
例如,mov [RSI],DL;将编译为2个字节和:mov [r8],DL; 将编译为3个字节
所以,如果我做了100到200次循环,r8会因为要解码的额外字节而变慢吗?或推动RSI并移动指针消除任何可能的速度增加?显然push和mov会在循环外发生.
我读过,例如Linux的某些部分是汇编,我猜他们会在汇编中编写,以加快执行速度
但是,现代内核开发人员在需要时实际上直接在汇编中编写,或者他们使用高级语言编写并使用编译器将其转换为汇编,并且他们使用转换后的汇编代码?
哪一个更好?考虑到编译器也有代码优化,是不是将高级转换为汇编更高效?我真的需要在汇编中编写内核的哪些部分?
我知道这int 0x80会在 linux 中造成中断。但是,我不明白这段代码是如何工作的。它会返回一些东西吗?
代表什么$ - msg?
global _start
section .data
msg db "Hello, world!", 0x0a
len equ $ - msg
section .text
_start:
mov eax, 4
mov ebx, 1
mov ecx, msg
mov edx, len
int 0x80 ;What is this?
mov eax, 1
mov ebx, 0
int 0x80 ;and what is this?
Run Code Online (Sandbox Code Playgroud) 我是计算机科学专业的学生.在我的第五学期,我必须学习汇编语言.在我班上6/7周后,我才知道这种汇编语言学习将教会我关于微处理器的知识.但我想知道2018年学习集会有什么优势???
我正在编写一个程序,将二进制值的十六进制表示转换为常规字符串.因此十六进制表示中的每个字符都将转换为字符串中的两个十六进制字符.这意味着结果将是两倍大小; 1字节的十六进制表示将需要字符串中的两个字节.
十六进制字符
0123456789 ;0x30 - 0x39
ABCDEF ;0x41 - 0x46
Run Code Online (Sandbox Code Playgroud)
例
0xF05C1E3A ;hex
4032568890 ;dec
Run Code Online (Sandbox Code Playgroud)
会成为
0x4630354331453341 ;hex
5057600944242766657 ;dec
Run Code Online (Sandbox Code Playgroud)
题?
是否有任何优雅/替代(/有趣)方法在这些状态之间进行转换,而不是查找表,(按位运算,移位,模数等)? 我不是在寻找库中的函数,而是如何实现/应该如何实现.有任何想法吗?