最近我在玩 freebsd 系统调用,我对 i386 部分没有问题,因为它在这里有很好的记录。但是我找不到 x86_64 的相同文档。
我看到人们在 linux 上使用相同的方式,但他们只使用程序集而不是 c。我想在我的例子中,系统调用实际上改变了一些被高优化级别使用的寄存器,所以它给出了不同的行为。
/* for SYS_* constants */
#include <sys/syscall.h>
/* for types like size_t */
#include <unistd.h>
ssize_t sys_write(int fd, const void *data, size_t size){
register long res __asm__("rax");
register long arg0 __asm__("rdi") = fd;
register long arg1 __asm__("rsi") = (long)data;
register long arg2 __asm__("rdx") = size;
__asm__ __volatile__(
"syscall"
: "=r" (res)
: "0" (SYS_write), "r" (arg0), "r" (arg1), "r" (arg2)
: "rcx", "r11", "memory"
); …Run Code Online (Sandbox Code Playgroud) 我试图了解Linux中内联汇编程序的一些内容.我正在使用以下功能:
void test_func(Word32 *var){
asm( " addl %0, %%eax" : : "m"(var) );
return;
}
Run Code Online (Sandbox Code Playgroud)
它生成以下汇编代码:
.globl test_func
.type test_func, @function
test_func:
pushl %ebp
movl %esp, %ebp
#APP
# 336 "opers.c" 1
addl 8(%ebp), %eax
# 0 "" 2
#NO_APP
popl %ebp
ret
.size test_func, .-test_func
Run Code Online (Sandbox Code Playgroud)
它将var mem地址与eax寄存器值相加而不是var值.
有没有办法告诉addl指令使用var值而不是var mem地址而不将var mem地址复制到寄存器?
问候
我知道这是一个非常基本的问题,但我真的很困惑.事实上,我绝对是gcc语法的新手.我希望在不使用扩展内联汇编的情况下拥有局部变量(事实上堆栈地址带有标签); 类似于intel语法中的代码:
DATA1 DB 100
MOV AL,DATA1
这是我猜可能在gcc中替代的代码:
- (int)someFunction:(int)x {
Run Code Online (Sandbox Code Playgroud)DATA1 DB 100 MOV AL, DATA1
但是这段代码导致了这个错误:
找不到架构x86_64的符号
我可以在x86中使用全局变量,但x64或x86_x64中的结果相同.
设置:LLVM 4.1; Xcode中使用的Cocoa 4
什么是正确的语法?
当使用内联汇编循环数组时,我应该使用寄存器修饰符"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) 我试图用rep movsb指令创建我的 memcpy 代码。当优化被禁用时,它适用于任何尺寸。但是,当我启用优化时,它没有按预期工作。
我从Intel® 64 and IA-32 Architectures Optimization Reference Manual section 3.7.6 中阅读了有关 memcpy 的增强 movsb 。我来到了 libc 源代码,我看到 libc 的默认 memcpy 使用 SSE 而不是movsb.
因此,我想比较memcpy 的SSE 指令和rep movsb之间的性能。但是现在,我发现它有些不对劲。
#include <stdio.h>
#include <string.h>
inline static void *my_memcpy(
register void *dest,
register const void *src,
register size_t n
) {
__asm__ volatile(
"mov %0, %%rdi;"
"mov %1, …Run Code Online (Sandbox Code Playgroud) 是否可以使用内联汇编块中的系统调用来编写单个字符?如果是这样,怎么样?它应该看起来像这样的"东西":
__asm__ __volatile__
(
" movl $1, %%edx \n\t"
" movl $80, %%ecx \n\t"
" movl $0, %%ebx \n\t"
" movl $4, %%eax \n\t"
" int $0x80 \n\t"
::: "%eax", "%ebx", "%ecx", "%edx"
);
Run Code Online (Sandbox Code Playgroud)
80美元是ascii中的'P',但是没有返回任何内容.
任何建议非常感谢!
当我尝试在Snow Leopard上运行使用gcc 4.2.1编译的代码时,我收到"总线错误"
#include <stdio.h>
/*__declspec(naked)*/ void
doStuff(unsigned long int val, unsigned long int flags, unsigned char *result)
{
__asm{
push eax
push ebx
push ecx
push edx
mov eax, dword ptr[esp + 24]//val
mov ebx, dword ptr[esp + 28]//flags
//mov ecx, dword ptr[esp + 32]//result
and eax, ebx
mov result, eax
pop edx
pop ecx
pop ebx
pop eax
ret
}
}
int main(int argc, char *argv[])
{
unsigned long val = 0xAA00A1F2;
unsigned long flags = 0x00100001;
unsigned …Run Code Online (Sandbox Code Playgroud) 我正在玩弄并试图了解计算机和程序的低级操作。为此,我正在尝试链接 Assembly 和 C。
我有2个程序文件:
“callee.c”中的一些C代码:
#include <unistd.h>
void my_c_func() {
write(1, "Hello, World!\n", 14);
return;
}
Run Code Online (Sandbox Code Playgroud)
我在“caller.asm”中还有一些 GAS x86_64 程序集:
.text
.globl my_entry_pt
my_entry_pt:
# call my c function
call my_c_func # this function has no parameters and no return data
# make the 'exit' system call
mov $60, %rax # set the syscall to the index of 'exit' (60)
mov $0, %rdi # set the single parameter, the exit code to 0 for normal exit
syscall
Run Code Online (Sandbox Code Playgroud)
我可以像这样构建和执行程序:
$ …Run Code Online (Sandbox Code Playgroud) 我编写了两个获取数组总和的函数,第一个是用 C++ 编写的,另一个是用内联汇编 (x86-64) 编写的,我比较了这两个函数在我的设备上的性能。
如果在编译期间未启用-O标志,则使用内联汇编的函数几乎比 C++ 版本快 4-5 倍。
cpp time : 543070068 nanoseconds
cpp time : 547990578 nanoseconds
asm time : 185495494 nanoseconds
asm time : 188597476 nanoseconds
Run Code Online (Sandbox Code Playgroud)
如果-O标志设置为-O1,它们会产生相同的性能。
cpp time : 177510914 nanoseconds
cpp time : 178084988 nanoseconds
asm time : 179036546 nanoseconds
asm time : 181641378 nanoseconds
Run Code Online (Sandbox Code Playgroud)
但是,如果我尝试将-O标志设置为-O2或-O3,则使用内联汇编编写的函数会得到不寻常的2-3 位纳秒性能,该性能速度很快(至少对我来说,请耐心等待,因为我对汇编编程没有扎实的经验,所以我不知道它与用 C++ 编写的程序相比有多快或多慢。)
cpp time : 177522894 nanoseconds
cpp time : 183816275 nanoseconds …Run Code Online (Sandbox Code Playgroud)gcc ×9
c ×6
assembly ×4
x86-64 ×3
linux ×2
optimization ×2
system-calls ×2
c++ ×1
freebsd ×1
macos ×1
performance ×1
scope ×1