内联汇编

详解内联汇编 有一些输出操作数在汇编代码中早早就被写入了新值A,在这之后,汇编代码才去读取某个输入操作数,这个输出操作数就被称为earlyclobber(早早就被改了)。所以,如果汇编代码中某个输出操作数是earlyclobber的,它的constraint就要加上“&”,这就是告诉编译器:给我分配一个单独的寄存器,别为了省事跟输入操作数用同一个寄存器。但是在C函数中写汇编代码,可以不用另外新建一个汇编文件,比较方便。第8行更新了%0的值后,第9行修改%1的值,由于%0、%1是同一个寄存器,所以%0的值也被修改了。 阅读详情
我爱南开站 -- ziyuan的个人文集
发信人: Thunder (小正哥), 信区: LinuxDev
标  题: Linux 中 x86 的内联汇编 ZZ
发信站: 我爱南开站 (2004年02月23日01:39:24 星期一), 站内信件

http://www-900.ibm.com/developerWorks/cn/linux/sdk/assemble/inline/index.shtml
 
 
Linux 中 x86 的内联汇编
将各个部分组合起来 
Bharata B. Rao (rbharata@in.ibm.com)
IBM Linux 技术中心,IBM 软件实验室,印度
2001 年 3 月

内容: 
 
 
GNU 汇编语法 
内联汇编 
汇编程序模板 
操作数 
修饰寄存器列表 
操作数约束 
一般约束 
用法示例 
使用寄存器约束 
使用匹配法约束 
使用内存操作数约束 
使用修饰寄存器 
结束语 
参考资料 
关于作者 
对本文的评价 
 
 
Bharata B. Rao 提供了在 Linux 平台上使用和构造 x86 
内联汇编的概括性介绍。他介绍了内联汇编及其各种用法的基础知识,提供了一些基本的
内联汇编编码指导,并解释了在 Linux 内核中内联汇编代码的一些实例。
如果您是 Linux 
内核的开发人员,您会发现自己经常要对与体系结构高度相关的功能进行编码或优化代码
路径。您很可能是通过将汇编语言指令插入到 C 
语句的中间(又称为内联汇编的一种方法)来执行这些任务的。让我们看一下 Linux 
中内联汇编的特定用法。(我们将讨论限制在 IA32 汇编。)

GNU 汇编程序简述
让我们首先看一下 Linux 中使用的基本汇编程序语法。GCC(用于 Linux 的 GNU C 
编译器)使用 AT&T 
汇编语法。下面列出了这种语法的一些基本规则。(该列表肯定不完整;只包括了与内联
汇编相关的那些规则。)

寄存器命名
寄存器名称有 % 前缀。即,如果必须使用 eax,它应该用作 %eax。

源操作数和目的操作数的顺序
在所有指令中,先是源操作数,然后才是目的操作数。这与将源操作数放在目的操作数之
后的 Intel 语法不同。



mov %eax, %ebx, transfers the contents of eax to ebx.


 

操作数大小
根据操作数是字节 (byte)、字 (word) 还是长型 (long),指令的后缀可以是 b、w 或 
l。这并不是强制性的;GCC 
会尝试通过读取操作数来提供相应的后缀。但手工指定后缀可以改善代码的可读性,并可
以消除编译器猜测不正确的可能性。




movb %al, %bl -- Byte move
    movw %ax, %bx -- Word move
    movl %eax, %ebx -- Longword move


 

立即操作数
通过使用 $ 指定直接操作数。



movl $0xffff, %eax -- will move the value of 0xffff into eax register.


 

间接内存引用
任何对内存的间接引用都是通过使用 ( ) 来完成的。

movb (%esi), %al -- will transfer the byte in the memory 










 pointed by esi into al
register


 

内联汇编
GCC 为内联汇编提供特殊结构,它具有以下格式:

GCG 的 "asm" 结构

   asm ( assembler template
    

: output operands               (optional)
    

: input operands                (optional)
    

: list of clobbered registers   
    (optional)
    

);  


 

本例中,汇编程序模板由汇编指令组成。输入操作数是充当指令输入操作数使用的 C 
表达式。输出操作数是将对其执行汇编指令输出的 C 表达式。

内联汇编的重要性体现在它能够灵活操作,而且可以使其输出通过 C 
变量显示出来。因为它具有这种能力,所以 "asm" 可以用作汇编指令和包含它的 C 
程序之间的接口。

一个非常基本但很重要的区别在于简单内联汇编只包括指令,而扩展内联汇编包括操作数
。要说明这一点,考虑以下示例:

内联汇编的基本要素

{
    int a=10, b;
    asm ("movl %1, %%eax;
    


movl %%eax, %0;"
        :"=r"(b)  /* output */    
        :"r"(a)       /* input */
        :"%eax"); /* clobbered register */
}


 

在上例中,我们使用汇编指令使 "b" 的值等于 "a"。请注意以下几点:

"b" 是输出操作数,由 %0 引用,"a" 是输入操作数,由 %1 引用。 
"r" 是操作数的约束,它指定将变量 "a" 和 "b" 
存储在寄存器中。请注意,输出操作数约束应该带有一个约束修饰符 
"=",指定它是输出操作数。 
要在 "asm" 内使用寄存器 %eax,%eax 的前面应该再加一个 %,换句话说就是 
%%eax,因为 "asm" 使用 %0、%1 等来标识变量。任何带有一个 % 
的数都看作是输入/输出操作数,而不认为是寄存器。 
第三个冒号后的修饰寄存器 %eax 告诉将在 "asm" 中修改 GCC %eax 的值,这样 GCC 
就不使用该寄存器存储任何其它的值。 
movl %1, %%eax 将 "a" 的值移到 %eax 中,movl %%eax, %0 将 %eax 的内容移到 "b" 
中。 
因为 "b" 被指定成输出操作数,因此当 "asm" 
的执行完成后,它将反映出更新的值。换句话说,对 "asm" 内 "b" 所做的更改将在 
"asm" 外反映出来。 
现在让我们更详细的了解每一项的含义。

汇编程序模板
汇编程序模板是一组插入到 C 
程序中的汇编指令(可以是单个指令,也可以是一组指令)。每条指令都应该由双引号括
起,或者整组指令应该由双引号括起。每条指令还应该用一个定界符结尾。有效的定界符
为新行 (/n) 和分号 (;)。 '/n' 后可以跟一个 tab(/t) 作为格式化符号,增加 GCC 
在汇编文件中生成的指令的可读性。 指令通过数 %0、%1 等来引用 C 
表达式(指定为操作数)。

如果希望确保编译器不会在 "asm" 内部优化指令,可以在 "asm" 后使用关键字 
"volatile"。如果程序必须与 ANSI C 兼容,则应该使用 __asm__ 和 
__volatile__,而不是 asm 和 volatile。

操作数
C 表达式用作 "asm" 内的汇编指令操作数。在汇编指令通过对 C 程序的 C 
表达式进行操作来执行有意义的作业的情况下,操作数是内联汇编的主要特性。

每个操作数都由操作数约束字符串指定,后面跟用括弧括起的 C 
表达式,例如:"constraint" (C 
expression)。操作数约束的主要功能是确定操作数的寻址方式。

可以在输入和输出部分中同时使用多个操作数。每个操作数由逗号分隔开。

在汇编程序模板内部,操作数由数字引用。如果总共有 n 
个操作数(包括输入和输出),那么第一个输出操作数的编号为 
0,逐项递增,最后那个输入操作数的编号为 n-1。总操作数的数目限制在 
10,如果机器描述中任何指令模式中的最大操作数数目大于 10,则使用后者作为限制。

修饰寄存器列表
如果 "asm" 中的指令指的是硬件寄存器,可以告诉 GCC 
我们将自己使用和修改它们。这样,GCC 
就不会假设它装入到这些寄存器中的值是有效值。通常不需要将输入和输出寄存器列为 
clobbered,因为 GCC 知道 "asm" 
使用它们(因为它们被明确指定为约束)。不过,如果指令使用任何其它的寄存器,无论
是明确的还是隐含的(寄存器不在输入约束列表中出现,也不在输出约束列表中出现),
寄存器都必须被指定为修饰列表。修饰寄存器列在第三个冒号之后,其名称被指定为字符
串。

至于关键字,如果指令以某些不可预知且不明确的方式修改了内存,则可能将 "memory" 
关键字添加到修饰寄存器列表中。这样就告诉 GCC 
不要在不同指令之间将内存值高速缓存在寄存器中。

操作数约束
前面提到过,"asm" 
中的每个操作数都应该由操作数约束字符串描述,后面跟用括弧括起的 C 
表达式。操作数约束主要是确定指令中操作数的寻址方式。约束也可以指定:

是否允许操作数位于寄存器中,以及它可以包括在哪些种类的寄存器中 
操作数是否可以是内存引用,以及在这种情况下使用哪些种类的地址 
操作数是否可以是立即数 
约束还要求两个操作数匹配。

常用约束
在可用的操作数约束中,只有一小部分是常用的;下面列出了这些约束以及简要描述。有
关操作数约束的完整列表,请参考 GCC 和 GAS 手册。

寄存器操作数约束 (r)
使用这种约束指定操作数时,它们存储在通用寄存器中。请看下例:



asm ("movl %%cr3, %0/n" :"=r"(cr3val));


 

这里,变量 cr3val 保存在寄存器中,%cr3 的值复制到寄存器上,cr3val 
的值从该寄存器更新到内存中。指定 "r" 约束时,GCC 可以将变量 cr3val 
保存在任何可用的 GPR 
中。要指定寄存器,必须通过使用特定的寄存器约束直接指定寄存器名。



a   %eax

b   %ebx

c   %ecx

d   %edx

S   %esi

D   %edi


 

内存操作数约束 (m)
当操作数位于内存中时,任何对它们执行的操作都将在内存位置中直接发生,这与寄存器
约束正好相反,后者先将值存储在要修改的寄存器中,然后将它写回内存位置中。但寄存
器约束通常只在对于指令来说它们是绝对必需的,或者它们可以大大提高进程速度时使用
。当需要在 "asm" 内部更新 C 
变量,而您又确实不希望使用寄存器来保存其值时,使用内存约束最为有效。例如,idtr 
的值存储在内存位置 loc 中:



 ("sidt %0/n" : :"m"(loc));



 

匹配(数字)约束
在某些情况下,一个变量既要充当输入操作数,也要充当输出操作数。可以通过使用匹配
约束在 "asm" 中指定这种情况。



asm ("incl %0" :"=a"(var):"0"(var));


 

在匹配约束的示例中,寄存器 %eax 既用作输入变量,也用作输出变量。将 var 
输入读取到 %eax,增加后将更新的 %eax 再次存储在 var 中。这里的 "0" 指定第 0 
个输出变量相同的约束。即,它指定 var 的输出实例只应该存储在 %eax 
中。该约束可以用于以下情况:

输入从变量中读取,或者变量被修改后,修改写回到同一变量中 
不需要将输入操作数和输出操作数的实例分开 
使用匹配约束最重要的意义在于它们可以导致有效地使用可用寄存器。

一般内联汇编用法示例
以下示例通过各种不同的操作数约束说明了用法。有如此多的约束以至于无法将它们一一
列出,这里只列出了最经常使用的那些约束类型。

"asm" 和寄存器约束 "r"
让我们先看一下使用寄存器约束 r 的 "asm"。我们的示例显示了 GCC 
如何分配寄存器,以及它如何更新输出变量的值。

int main(void)
{
    int x = 10, y;
    
    asm ("movl %1, %%eax;
    

 "movl %%eax, %0;"
        :"=r"(y)  /* y is output operand */
        :"r"(x)       /* x is input operand */
        :"%eax"); /* %eax is clobbered register */
}



 

在该例中,x 的值复制为 "asm" 中的 y。x 和 y 都通过存储在寄存器中传递给 
"asm"。为该例生成的汇编代码如下:



main:




pushl %ebp




movl %esp,%ebp




subl $8,%esp




movl $10,-4(%ebp)    




movl -4(%ebp),%edx  /* x=10 is stored in %edx */
#APP    /* asm starts here */   




movl %edx, %eax     /* x is moved to %eax */




movl %eax, %edx     /* y is allocated in edx and updated */

#NO_APP /* asm ends here */




movl %edx,-8(%ebp)  /* value of y in stack is updated with 
                
 the value in %edx */ 


 

当使用 "r" 约束时,GCC 在这里可以自由分配任何寄存器。在我们的示例中,它选择 
%edx 来存储 x。在读取了 %edx 中 x 的值后,它为 y 也分配了相同的寄存器。

因为 y 是在输出操作数部分中指定的,所以 %edx 中更新的值存储在 -8(%ebp),堆栈上 
y 的位置中。如果 y 是在输入部分中指定的,那么即使它在 y 的临时寄存器存储值 
(%edx) 中被更新,堆栈上 y 的值也不会更新。

因为 %eax 是在修饰列表中指定的,GCC 不在任何其它地方使用它来存储数据。

输入 x 和输出 y 都分配在同一个 %edx 
寄存器中,假设输入在输出产生之前被消耗。请注意,如果您有许多指令,就不是这种情
况了。要确保输入和输出分配到不同的寄存器中,可以指定 & 
约束修饰符。下面是添加了约束修饰符的示例。



int main(void)
{
    int x = 10, y;
    
    asm ("movl %1, %%eax;
    

 "movl %%eax, %0;"
        :"=&r"(y) /* y is output operand, note the    
                
 & constraint modifier. */
        :"r"(x)       /* x is input operand */
        :"%eax"); /* %eax is clobbered register */
}


 

以下是为该示例生成的汇编代码,从中可以明显地看出 x 和 y 存储在 "asm" 
中不同的寄存器中。



main:




pushl %ebp




movl %esp,%ebp




subl $8,%esp




movl $10,-4(%ebp)




movl -4(%ebp),%ecx  /* x, the input is in %ecx */
#APP
    movl %ecx, %eax
    movl %eax, %edx     /* y, the output is in %edx */

#NO_APP




movl %edx,-8(%ebp)


 

特定寄存器约束的使用
现在让我们看一下如何将个别寄存器作为操作数的约束指定。在下面的示例中,cpuid 
指令采用 %eax 
寄存器中的输入,然后在四个寄存器中给出输出:%eax、%ebx、%ecx、%edx。对 cpuid 
的输入(变量 "op")传递到 "asm" 的 eax 寄存器中,因为 cpuid 
希望它这样做。在输出中使用 a、b、c 和 d 约束,分别收集四个寄存器中的值。



asm ("cpuid"








: "=a" (_eax),









"=b" (_ebx),









"=c" (_ecx),









"=d" (_edx)








: "a" (op));



 

在下面可以看到为它生成的汇编代码(假设 _eax、_ebx 等... 变量都存储在堆栈上):




movl -20(%ebp),%eax /* store 'op' in %eax -- input */
#APP




cpuid
#NO_APP




movl %eax,-4(%ebp)  /* store %eax in _eax -- output */




movl %ebx,-8(%ebp)  /* store other registers in




movl %ecx,-12(%ebp) 
 respective output variables */





movl %edx,-16(%ebp)


 

strcpy 函数可以通过以下方式使用 "S" 和 "D" 约束来实现:



asm ("cld/n
    


rep/n
    


movsb"
    


: /* no input */
    


:"S"(src), "D"(dst), "c"(count));


 

通过使用 "S" 约束将源指针 src 放入 %esi 中,使用 "D" 约束将目的指针 dst 放入 
%edi 中。因为 rep 前缀需要 count 值,所以将它放入 %ecx 中。

在下面可以看到另一个约束,它使用两个寄存器 %eax 和 %edx 将两个 32 
位的值合并在一起,然后生成一个64 位的值:


#define rdtscll(val) /


 __asm__ __volatile__ ("rdtsc" : "=A" (val))

The generated assembly looks like this (if val has a 64 bit memory space).

#APP




rdtsc
#NO_APP




movl %eax,-8(%ebp)  /* As a result of A constraint 




movl %edx,-4(%ebp)  
 %eax and %edx serve as outputs */

Note here that the values in %edx:%eax serve as 64 bit output.


 

使用匹配约束
在下面将看到系统调用的代码,它有四个参数:



#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) /
type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) /
{ /
long __res; /
__asm__ volatile ("int $0x80" /




: "=a" (__res) /




: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), /





"d" ((long)(arg3)),"S" ((long)(arg4))); /
__syscall_return(type,__res); /
}


 

在上例中,通过使用 b、c、d 和 S 约束将系统调用的四个自变量放入 
%ebx、%ecx、%edx 和 %esi 中。请注意,在输出中使用了 "=a" 约束,这样,位于 %eax 
中的系统调用的返回值就被放入变量 __res 中。通过将匹配约束 "0" 
用作输入部分中第一个操作数约束,syscall 号 __NR_##name 被放入 %eax 
中,并用作对系统调用的输入。这样,这里的 %eax 
既可以用作输入寄存器,又可以用作输出寄存器。没有其它寄存器用于这个目的。另请注
意,输入(syscall 号)在产生输出(syscall 的返回值)之前被消耗(使用)。

内存操作数约束的使用
请考虑下面的原子递减操作:



__asm__ __volatile__(








"lock; decl %0"








:"=m" (counter)








:"m" (counter));


 

为它生成的汇编类似于:



#APP
    lock
    decl -24(%ebp) /* counter is modified on its memory location */
#NO_APP.


 

您可能考虑在这里为 counter 使用寄存器约束。如果这样做,counter 
的值必须先复制到寄存器,递减,然后对其内存更新。但这样您会无法理解锁定和原子性
的全部意图,这些明确显示了使用内存约束的必要性。

使用修饰寄存器
请考虑内存拷贝的基本实现。

   asm ("movl $count, %%ecx;
    


up: lodsl;  
    


stosl;
    


loop up;"
        :           /* no output */
        :"S"(src), "D"(dst) /* input */
        :"%ecx", "%eax" );  /* clobbered list */    


 

当 lodsl 修改 %eax 时,lodsl 和 stosl 指令隐含地使用它。%ecx 寄存器明确装入 
count。但 GCC 在我们通知它以前是不知道这些的,我们是通过将 %eax 和 %ecx 
包括在修饰寄存器集中来通知 GCC 的。在完成这一步之前,GCC 假设 %eax 和 %ecx 
是自由的,它可能决定将它们用作存储其它的数据。请注意,%esi 和 %edi 由 "asm" 
使用,它们不在修饰列表中。这是因为已经声明 "asm" 
将在输入操作数列表中使用它们。这里最低限度是,如果在 "asm" 
内部使用寄存器(无论是明确还是隐含地),既不出现在输入操作数列表中,也不出现在
输出操作数列表中,必须将它列为修饰寄存器。

结束语
总的来说,内联汇编非常巨大,它提供的许多特性我们甚至在这里根本没有涉及到。但如
果掌握了本文描述的基本材料,您应该可以开始对自己的内联汇编进行编码了。

参考资料

请参考 Using and Porting the GNU Compiler Collection (GCC) 手册。 
请参考 GNU Assembler (GAS) 手册。 
仔细阅读 Brennan's Guide to Inline Assembly。 
关于作者
Bharata B. Rao 拥有印度 Mysore 大学的电子和通信工程的学士学位。他从 1999 
年就开始为 IBM Global Services, India 工作了。他是 IBM Linux 
技术中心的成员之一,他在该中心中主要从事 Linux 
RAS(可靠性、可用性和适用性)的研究。他感兴趣的其它领域包括操作系统本质和处理
器体系结构。可以通过 rbharata@in.ibm.com 与他联系。

返回上一页 Telnet样式阅览本文
如何在c代码里内联汇编 一:背景 早期,绝大多数的程序都是用汇编语言写的,甚至是计算机的操作系统OS/360.但是,汇编语言因其抽象程度低,无法提供类型检查。使得编写大型程序捉襟见肘。而且,汇编代码是和机器紧紧联系在一起,使得汇编语言编写的程序移植性差。 那为什么还要把汇编代码内联到c语言里呢? 二:汇编代码的优势 1.访问寄存器的值 2.访问条件码 3.使用一些特殊的指令和特殊的内存地址 …… ... 阅读详情

相关推荐

GD-Link离线烧录全攻略:从配置到一键下载的保姆级教程

本文详细介绍了GD-Link离线烧录的全流程,从硬件准备到软件配置,再到一键下载的实战技巧。通过保姆级教程,帮助工程师快速掌握国产MCU的离线烧录技术,适用于产线批量烧录和现场设备维护等场景,显著提升工作效率。

ww90123的博客 649

汇编1

.data hello:.ascii "hello" .text .global _start _start: movl $4,%eax movl $1,%ebx movl $hello,%ecx movl $5,%edx int $0x80 eax:4 ebx:1,write系统调用,1代表STDOUT_FILENO .global _start _start: movl $1,%ea

A1157599735的专栏 7万+

汽车软件工程师必看:ASPICE开发流程全解析(附各阶段交付物清单)

本文全面解析了汽车行业广泛采用的ASPICE开发流程,详细介绍了从需求挖掘到系统架构设计、软件工程及测试验证各阶段的关键操作和交付物清单。针对汽车软件工程师,提供了实用的协作指南和工具推荐,帮助团队提升开发效率并降低项目风险,是掌握ASPICE标准的必备指南。

weixin_30733003的博客 640

Linux Kernel 源码学习必备知识之:GCC 内联汇编(AT&T格式)

原因是即使寄存器只变动一部分,它的整体也会全跟着受影响,所以在 clobber/modiy 句中声明寄存器时,可以用低 8 位名称、低 16 位名称或低 32 位或全 64 位名称,如"al"、"ax"、"eax"、"rax" 都是指 rax 寄存器,其他通用寄存器也是一样的。单独强调一下,以上的 output() 和 intput() 括号中的是 C 代码中的变量,output(C变量)和input(C变量) 就像 C 语言中的函数,将 C 变量(值或变量地址)转换成汇编代码的操作数。

嵌入式Linux内核的博客 3333

【asrpro语音模块+语音控制小风扇】

智能语音控制小风扇,使用ASRPRO语音模块只要一句话就能设置小风扇不同挡位的风力。图形化编程简单有效的控制输出PWM的占空比。

qq_57234300的博客 1万+

ADXL355 STM32 HAL 库 SPI 驱动实战:从零构建高精度加速度数据采集系统

本文详细介绍了如何使用STM32 HAL库通过SPI接口驱动ADXL355高精度加速度计,构建稳定可靠的数据采集系统。从硬件连接到寄存器配置,再到数据采集与处理,提供了完整的实战代码和优化技巧,特别适合工业级振动监测等应用场景。

weixin_28738397的博客 324

C语言内联汇编

内联汇编称为inline assembly,GCC支持在C代码中直接嵌入汇编代码,所以称为GCC inline assembly。大家知道,C语言不支持寄存器操作,汇编语言可以,所以自然就想到了在C语言中嵌入内联汇编提升“战斗力”的方式,通过内联汇编,C程序员可以实现C语言无法表达的功能,这样使开发能力大为提升。

Lyajpunov的博客 2866

Python | 处理CMIP6 NC数据,以tas为例

各位同学,一般在文章最后一章我们可能会做不同气候情景下变量的未来时空变化特征,类似上图。从cmip6下载的nc数据常需要转换格式、裁剪到研究区和重采样等,本期代码可以解决这类问题。

qq_48539301的博客 1384

C语言进阶——内联汇编

内联函数 在 C 语言中,我们可以指定编译器将一个函数代码直接复制到调用其代码的地方执行。这种函数调用方式和默认压栈调用方式不同,我们称这种函数为内联函数。有点像宏。 优点:内联函数降低了函数的调用开销。 实现:指定编译器将一个函数处理为内联函数,我们只要在函数声明前加上 inline 关键字就可以了。 内联汇编 基于对上述内联函数的认知,我们大概可以想象出内联汇编到底是怎么一回事了。内联汇编相当于用汇编语句写成的内联函数。 优点:效率高。 实现:使用 asm 关键字。 关键:之所以内联汇编如此有用,主要

lyndon 3万+

FPGA_adc采样并通过以太网发送到上位机

本项目使用FPGA-ZYNQ-7020采集8通道ADC数据,通过以太网上传到上位机显示波形PL部分包括数据的获取与处理,数据从PL传递到PSPS部分包括以太网的发送,由PL到PS的中断触发本文章不详细讲解背后原理 但保证每一步足够详细,跟着就能实现。本人FPGA平台 大磊FPGA7020开发板 vivado2020.2 vitis2020.2 匿名上位机公开版

weixin_42304868的博客 5624

【QGIS】【OsGeo4w】安装方法

every blog every motto: You will never know unless you try 0. 前言 因为目前要使用QGIS,然而环境配置就整了大半天,哎,进行简单记录,方便自己方便他人。 一共分为两种方式安装: 独立安装包 网络安装包(下载osgeo4w-setup) QGIS提供了不同的版本: 长期发行版(LTR) 最新版(LR) 开发人员版本(DEV,母版或测试版) 说明: 本文推荐第二种 1. 正文 1.1 下载osgeo4w 下载链接 下载完成: 1.2

胡侃有料的博客 2万+

ARM64内联汇编

ARM64内联汇编简单介绍

小立仔 3978

NLP高频面试题(三十一)——多模态预训练模型的主要结构、特征对齐与融合方法及对比损失函数详解

多模态预训练模型通过创新的架构设计和训练策略,在跨模态理解和表示学习上取得了显著进展。从单塔到双塔,从编码器-解码器混合到图结构模型,研究者们探索了不同的模态融合途径;配合显式与隐式对齐手段以及有效的对比学习损失,当前的多模态模型已经能够在图文检索、视觉问答、图像描述生成等任务上接近甚至超越专门的有监督模型。可以说,多模态预训练成为了继NLP和CV单模态预训练之后的又一个AI热点领域。模型规模与泛化:与单模态的大型预训练模型类似,多模态模型的参数规模和训练数据规模在迅速增长。

WeLearnNLP 2924

内联汇编语法说明

为什么使用内嵌汇编? ——解决一些无法直接用C或C++实现的功能,比如C中没有现成的函数或语法可用。 内联汇编的使用原理: 在内嵌汇编中,可以将C语言变量指定为汇编指令的操作数,而且不用去管如何将C语言变量的值读入哪个寄存器,以及如何将计算结果写回C变量,你只要告诉程序中C语言变量与汇编指令操作数之间的对应关系即可, GCC会自动插入代码完成必要的操作。 使用内嵌汇编,要先编写汇编指令...

qq_41230365的博客 6800

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

VS2019 内联汇编开发

前言 上个月有点懒, 炒股和玩游戏把时间占满了, 而且一时间没想到特别想写的文章. 这个月争取开个好头. 首先什么是内联汇编? 内联汇编是在C,C++代码内部嵌入一部分汇编代码, 这部分代码会被编译器跳过直接拼接. 为什么要用内联汇编? 这种情况一般是由于我们对于当前的编译器的能力感到不满意, 所以需要代替编译器来优化一些代码片段. 当然我们可以完全进行汇编实现, 直接把函数写成一个.asm汇编文件(这个文件可以用yasm, nasm, masm进行编译为object文件参与代码链接). 内联..

luoyu510183的博客 1万+

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

C++中使用内联汇编

很多的时候可以采用__asm{}的形式就可以嵌入汇编代码 #include <stdio.h> int power2(int num, int power); void main(void) { printf("%d\n", power2(3,3)); } int power2(int num, int power) { __asm { push eax ...

junehappylove(王俊伟)的专栏 6738

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

[ARM]内联汇编

内联汇编语法 语法 (1)asm ​ 这块直接写做 __asm__ ​ 表示这是一段内联汇编。 (2)asm-qualifiers ​ 这里取值有三种 volatile , inline , goto: ​ volatile的意思是易变的、不稳定的,用来告诉编译器不要随便优化这段代码,否则可能出问题。比如汇编指令“mov r0, r0”,它把r0的值复制到r0,并没有实际做什么事情,你的本意可能是用这条指令来延时。编译器看到这指令后,可能就把它去掉了。加上volatile的话,编译器就不会擅自优化。

myprogram_player的博客 6090

asm内联汇编

内联汇编   内联汇编是指在 C/C++ 代码中嵌入的汇编代码,与全部是汇编的汇编源文件不同,它们被嵌入到 C/C++ 的大环境中。 一、gcc 内联汇编   gcc 内联汇编的格式如下: asm ( 汇编语句 : 输出操作数 // 非必需 : 输入操作数 // 非必需 : 其他被污染的寄存器 // 非必需 );   我们通过一个简单的例子来了解一下它的格式(gcc_add.c): #include <stdio.h&g..

wyyy2088511的博客 1640

汇编指令和内联汇编_内联汇编-从头开始

对于C / C ++程序员而言,内联汇编并不是一项新功能,可帮助我们充分利用计算能力。 但是,大多数程序员很少改变这种做法。 实际上,内联汇编仅满足特定的要求,尤其是在涉及高级编程语言的最前沿时。 本文介绍了有关IBM POWER处理器体系结构的两种方案。 使用本文提供的示例,我们可以找出在哪里应用内联汇编。 方案1:一个更好的库 C / C ++编程语言支持逻辑操作。 因此,在该...

cusi77914的博客 2702

Solidity 内联汇编

       最近大致浏览了一下Aragon的DAO框架合约,Solidity编写的源代码里使用了很多内联汇编。虽然这种做法有待商榷,但它表明了熟练使用Solidity内联汇编的必要性与紧迫性。优快云上已经有很多人做了Solidity汇编这一章节的翻译并且翻译的很好,但是:纸上得来终觉浅,绝知此事要躬行, 并且版本且更新,还是...

天草降临的博客 2572

内联汇编 - 从头开始

对于 C/C++ 程序员来说,内联汇编并不是一个新特性,它可以帮助我们充分利用计算能力。然而,大多数程序员很少有机会实际使用该特性。事实上,内联汇编只为特定的要求提供服务,在涉及先进的高层编程语言时尤其如此。 本文介绍了 IBM Power 处理器架构的两个场景。使用本文提供的示例,我们可以发现在什么地方应用了内联汇编。 场景 1:更好的库 C/C++ 编程语言支持逻辑运算。在本例中,用户使...

phenixyf的专栏 1万+
上一篇: jmp指令
下一篇: make 中的config详述
smallgeneral
博客等级 码龄19年 10粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值