当使用内联汇编循环数组时,我应该使用寄存器修饰符"r"还是内存修饰符"m"?
让我们考虑其将两个浮标阵为例x,与y和结果写入z.通常我会使用内在函数这样做
for(int i=0; i<n/4; i++) {
__m128 x4 = _mm_load_ps(&x[4*i]);
__m128 y4 = _mm_load_ps(&y[4*i]);
__m128 s = _mm_add_ps(x4,y4);
_mm_store_ps(&z[4*i], s);
}
Run Code Online (Sandbox Code Playgroud)
这是我使用寄存器修饰符"r"提出的内联汇编解决方案
void add_asm1(float *x, float *y, float *z, unsigned n) {
for(int i=0; i<n; i+=4) {
__asm__ __volatile__ (
"movaps (%1,%%rax,4), %%xmm0\n"
"addps (%2,%%rax,4), %%xmm0\n"
"movaps %%xmm0, (%0,%%rax,4)\n"
:
: "r" (z), "r" (y), "r" (x), "a" (i)
:
);
}
}
Run Code Online (Sandbox Code Playgroud)
这会产生与GCC类似的组装.主要区别在于GCC将16添加到索引寄存器并使用1的标度,而内联汇编解决方案将4添加到索引寄存器并使用4的标度.
我无法使用通用寄存器作为迭代器.在这种情况下,我必须指定一个rax.是否有一个原因?
这是我想出的使用内存修饰符"m"的解决方案
void add_asm2(float *x, float *y, …Run Code Online (Sandbox Code Playgroud) main为什么我不能在基本 asm 内联中使用局部变量?它只允许在扩展汇编中使用,但为什么会这样呢?
(我知道局部变量在返回地址之后位于堆栈上(因此一旦函数返回就不能使用),但这不应成为不使用它们的原因)
以及基本汇编的示例:
int a = 10; //global a
int b = 20; //global b
int result;
int main() {
asm ( "pusha\n\t"
"movl a, %eax\n\t"
"movl b, %ebx\n\t"
"imull %ebx, %eax\n\t"
"movl %eax, result\n\t"
"popa");
printf("the answer is %d\n", result);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
扩展的例子:
int main (void) {
int data1 = 10; //local var - could be used in extended
int data2 = 20;
int result;
asm ( "imull %%edx, %%ecx\n\t"
"movl %%ecx, %%eax"
: "=a"(result) …Run Code Online (Sandbox Code Playgroud) 我正在探索在C++源代码中包含汇编.现在看来,这始于一个电话asm(),但我也看到了_asm()和__asm().下划线之间有什么区别?如果相关,我最感兴趣的是GNU编译器.
编辑:来自这个论坛
_asm - simply invokes the inline assembler
__asm - is treated like an intrinsic function call
Run Code Online (Sandbox Code Playgroud)
不确定这是真的还是胡扯?
我一直在用C编写内核.我一直在使用GCC交叉编译器,在Windows系统上编写并以16位实模式为目标.我没有可用于编写内核的C库.我已经开始使用一些代码来假设将字符直接打印到屏幕上.这是一个函数来自kernel.c:
int main()
{
char *src = (char *)0xB8000000L;
*src = 'M';
src += 2;
*src = 'D';
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我使用GCC编译了我的代码,并使用参数-m16生成将在实模式下运行的代码.我使用这些命令来生成我的kernel.bin:
gcc -ffreestanding -c -m16 kernel.c -o kernel.o
ld -Ttext 0x10000 -o kernel.pe kernel.o
objcopy -O binary kernel.pe kernel.bin
Run Code Online (Sandbox Code Playgroud)
Stack Overflow用户Michael Petch解决了我的链接器问题,但评论代码本身是不正确的.他发表了这样的评论:
除链接器问题外,您是否尝试将旧的TurboC/MSVC 16位代码转换为GCC?我发现(char*)0xB8000000L可疑.如果它是一个真正的16位C编译器,它可能是好的,如果它是(char far*)0xB8000000L.GCC不是一个真正的16位C编译器,并没有旧式远指针的概念.所以,即使你得到这个代码进行编译,这可能不会做你认为它做的,我假设从-m16选项与GCC你正在尝试创建一个实模式16位内核(而不是保护模式一个) )?
我一直在尝试printf在C中为我自己的操作系统实现自己的类似功能.我上面提供的代码只是我理解的一小部分.我在程序集中创建了一个bootloader(8086).
迈克尔是对的吗?如果是这样,我该如何解决这个问题并直接写入视频内存0xb8000?
我试图理解汇编语言的语法,首先正确地编写代码,然后高效地编写代码。在此示例中,它显示了使用的示例"=r"
asm volatile ("MRS %0, PMUSERENR_EL0\n": "=r"(value));
Run Code Online (Sandbox Code Playgroud)
这会读取寄存器的值并将其存储在值变量中。另一个例子使用::"r"
asm volatile ("MSR PMUSERENR_EL0, %0\n":: "r"(value));
Run Code Online (Sandbox Code Playgroud)
这会将值变量写入 PMUSERENR_ELO 寄存器。这是另一个例子:如何测量 ARM Cortex-A8 处理器中的程序执行时间?。
当我尝试使用上述两个命令编译一个简单的测试代码时,我收到错误::9:2: error: output operand constraint lacks '='如果我添加“=”并删除一个“:”,它将编译,但当我测试它时,它只是说Illegal instruction
如果有人可以解释其中的差异,这将很有帮助,许多组装教程显示相同的格式但没有解释。如果这提供了任何见解的话,它是在 64 位 ARM 平台上进行的。谢谢。
从我之前的问题中考虑这段代码.
int main(){
asm("movq $100000000, %rcx;"
"startofloop: ; "
"sub $0x1, %rcx; "
"jne startofloop; ");
}
Run Code Online (Sandbox Code Playgroud)
我想将循环的迭代次数变为C变量,所以在阅读本文后我尝试了以下内容.
int main(){
int count = 100000000;
asm("movq %0, %rcx;"
"startofloop: ; "
"sub $0x1, %rcx; "
"jne startofloop; ":: "r"(count));
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,这无法编译,并打破以下错误.
asm_fail.c: In function ‘main’:
asm_fail.c:3:5: error: invalid 'asm': operand number missing after %-letter
asm("movq %0, %rcx;"
^
asm_fail.c:3:5: error: invalid 'asm': operand number missing after %-letter
Run Code Online (Sandbox Code Playgroud)
将C变量的值传递给程序集的正确方法是什么?
我不明白为什么这段代码中的 CALL 函数不起作用:
#include<stdio.h>
void main() {
__asm {
jmp L1
L2:
mov eax, 8
ret
L1:
call L2
}
}
Run Code Online (Sandbox Code Playgroud)
如果我一步一步调试代码,'call L1'行没有被处理,程序直接跳到最后。怎么了?我正在使用 Intel 32 位寄存器开发 VisualStudio2015。
我已经实现了strlen()以不同的方式,包括功能SSE2 assembly,SSE4.2 assembly并且SSE2 intrinsic,我也产生了一些实验,请用strlen() in <string.h>和strlen() in glibc。但是,以毫秒(时间)为单位的性能是出乎意料的。
我的实验环境:
CentOS 7.0 + gcc 4.8.5 + Intel Xeon
以下是我的实现:
strlen 使用SSE2程序集
long strlen_sse2_asm(const char* src){
long result = 0;
asm(
"movl %1, %%edi\n\t"
"movl $-0x10, %%eax\n\t"
"pxor %%xmm0, %%xmm0\n\t"
"lloop:\n\t"
"addl $0x10, %%eax\n\t"
"movdqu (%%edi,%%eax), %%xmm1\n\t"
"pcmpeqb %%xmm0, %%xmm1\n\t"
"pmovmskb %%xmm1, %%ecx\n\t"
"test %%ecx, %%ecx\n\t"
"jz lloop\n\t"
"bsf %%ecx, %%ecx\n\t"
"addl %%ecx, %%eax\n\t"
"movl %%eax, %0"
:"=r"(result)
:"r"(src)
:"%eax" …Run Code Online (Sandbox Code Playgroud)我试图编译Zend引擎的这个溢出检测宏:
#define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do { \
long __tmpvar; \
__asm__( \
"mul %0, %2, %3\n" \
"smulh %1, %2, %3\n" \
"sub %1, %1, %0, asr #63\n" \
: "=X"(__tmpvar), "=X"(usedval) \
: "X"(a), "X"(b)); \
if (usedval) (dval) = (double) (a) * (double) (b); \
else (lval) = __tmpvar; \
} while (0)
Run Code Online (Sandbox Code Playgroud)
并在装配中得到了这个结果:
; InlineAsm Start
mul x8, x8, x9
smulh x9, x8, x9
sub x9, x9, x8, asr #63
; InlineAsm End
Run Code Online (Sandbox Code Playgroud)
编译器仅对宏的输入和输出使用2个寄存器,我认为它必须至少为3,并导致错误的计算结果(例如,-1*-1).有什么建议吗?
我试图在GCC中使用以下代码.它抛出错误(我猜是因为__asm).为什么这种简单易用的格式在GCC中不起作用?这里提供了扩展汇编的语法.当在内联汇编中使用更多变量时,我感到困惑.有人可以将以下程序转换为适当的形式,并在有变量使用的地方给出必要的解释.
int time, subtime;
float x = 5.0f;
__asm {
cpuid
rdtsc
mov subtime, eax
cpuid
rdtsc
sub eax, subtime
mov subtime, eax // Only the last value of subtime is kept
// subtime should now represent the overhead cost of the
// MOV and CPUID instructions
fld x
fld x
cpuid // Serialize execution
rdtsc // Read time stamp to EAX
mov time, eax
fdiv // Perform division
cpuid // Serialize …Run Code Online (Sandbox Code Playgroud)