当前位置: 技术问答>linux和unix
请教各位,Linux下的汇编怎么搞?
来源: 互联网 发布时间:2015-03-18
本文导语: 哪位高手指点一下,怎样在Linux下用汇编开发,用什么工具,什么样的汇编语法等等,谢了! | gcc中的:(计算a+b) int main() { int a,b,c; a=23; b=45; asm ("movl %1,%%eax; movl %2,...
哪位高手指点一下,怎样在Linux下用汇编开发,用什么工具,什么样的汇编语法等等,谢了!
|
gcc中的:(计算a+b)
int main() {
int a,b,c;
a=23;
b=45;
asm ("movl %1,%%eax;
movl %2,%%ebx;
addl %%ebx,%%eax;
movl %%eax,%0"
:"=g"(c)
:"g"(a),"g"(b)
:"%eax","%ebx");
printf("c=%dn",c);
}
int main() {
int a,b,c;
a=23;
b=45;
asm ("movl %1,%%eax;
movl %2,%%ebx;
addl %%ebx,%%eax;
movl %%eax,%0"
:"=g"(c)
:"g"(a),"g"(b)
:"%eax","%ebx");
printf("c=%dn",c);
}
|
我就说的通俗一点
取/引用寄存器里的值要: %eax 如 movl %eax,%ebx
将寄存器里的值作为指针取指针指向的值要: (%eax).
取指针值的一般形式为: _偏移(_基址,_索引,步长)==_基址+_索引*步长+_偏移;_偏移为变量或常量.
取/引用变量或常量的值要: $0x7c00,$_variable. 如 movl $0x7c00,%eax
取变量或常量指针所指向的值为: 0x7c00,_variableptr。
其实观察不难发现:取指针所指向的值不管是常量,变量还是寄存器其实都是
取指针值的一般形式的特殊形式而已。
取/引用寄存器里的值要: %eax 如 movl %eax,%ebx
将寄存器里的值作为指针取指针指向的值要: (%eax).
取指针值的一般形式为: _偏移(_基址,_索引,步长)==_基址+_索引*步长+_偏移;_偏移为变量或常量.
取/引用变量或常量的值要: $0x7c00,$_variable. 如 movl $0x7c00,%eax
取变量或常量指针所指向的值为: 0x7c00,_variableptr。
其实观察不难发现:取指针所指向的值不管是常量,变量还是寄存器其实都是
取指针值的一般形式的特殊形式而已。
|
你要为什么cpu写程序,你总的有一个该cpu编译程序吧,有好多cpu提供了linux下的编译工具
然后你就用vi编辑,编译,查错...... 就可以啦。当然,你也可以为你的汇编程序写一个开发工具,一个仿真器等等,呵呵,高手啦
我在linux下作过1024,6502,arm等等的ap,大概就是这么一个过程
然后你就用vi编辑,编译,查错...... 就可以啦。当然,你也可以为你的汇编程序写一个开发工具,一个仿真器等等,呵呵,高手啦
我在linux下作过1024,6502,arm等等的ap,大概就是这么一个过程
|
linux下面一般用三种工具
as86: 简单的intel汇编指令
nasm: 支持比较复杂的intel汇编(流行)
gas/as: 支持at&t的汇编指令,linux内核中的汇编就是用它
as86: 简单的intel汇编指令
nasm: 支持比较复杂的intel汇编(流行)
gas/as: 支持at&t的汇编指令,linux内核中的汇编就是用它
|
一般来说有两种方法,一种方法是用GCC的内嵌汇编,具体信息可以
info ar
另一种方法是用NASM,可以man nasm
info ar
另一种方法是用NASM,可以man nasm
|
贴一个老文档,去年写的,大家看看有问题没有 :)
在c代码中嵌入汇编
1.简介
本文介绍在c代码中嵌入汇编语言的方法,所有的方法仅对gcc(Gnu C Compiler)有效。由于作者是在一台pc上进行的实验,所以例子中如果未加说明,所有的汇编代码均为x86汇编。本文的唯一参考资料就是gcc Manual,其中的5.36小节介绍了在c中嵌入汇编的办法。
2.如何在c中嵌入汇编代码
2.1.最简单的情形
在gcc里有一个asm表达式,用于实现嵌入汇编。就像这样
asm("xor %%eax, %%eax");
这个汇编指令的作用是吧eax寄存器清零,你也许注意到这些代码和我们常见的x86汇编代码有些不同,的确,gcc使用的汇编格式是AT&T格式而不是DOS下常见的Intel格式,它们之间主要区别有:AT&T格式的寄存器使用%标志开头,例如Intel格式中的EAX在这里写作%eax;AT&T格式的目的操作数是后一个而不像Intel格式那样是前一个,比如:
asm("movl %%eax, %%ebx");
是将eax寄存器的值移到ebx。另外还有一些区别,比如内存地址的表示方法等等,详情可以参考DJGPP FAQ里的Coverting between Intel ASM syntax and AT&T syntax。
另外还要注意%号在asm表达式里是特殊字符,所以%eax前面要再加一个%号进行转义,这样就成了"%%eax"这样的寄存器表示方法,如果你用的是Sparc之类的cpu,寄存器使用"r1""r5"之类的表达式,就不需要累赘的%号了。
为了比较易读,多行的汇编代码可以写成这样
asm("xor %%eax, %%eax
movl -20(%%ebp), %%ebx
sub %%ebx, %%eax");
不过在最新的gcc-3系列里一个字符串写了一行以上是会引发一个warning的,让人看了不舒服,这样写就不会了:
asm("xor %%eax, %%eax nt"
"movl -20(%%ebp), %%ebx nt"
"sub %%ebx, %%eax");
n就是换行,t是tab对齐,这下明白了吧 :)
2.2.使用c中定义的变量
先给出一个例子:
int foo;
asm("movl %%eax, %0"
: "=g" (foo));
在asm()中,在冒号分隔符后面声明你的变量,括号中是变量名(foo),"=g"表示这是一个作为输出的整型变量,如果变量是作为输入的话,就要放在第二个括号分隔符后面,象这样:
int foo1,foo2;
asm("movl %1, %%eax nt"
"movl %%eax, %0"
: "=g" (foo1)
: "g" (foo2));
程序是把foo2的内容赋给foo1。从这个例子可以看到,变量在汇编语言里被引用的时候表示符是该变量在asm()里被声明的位置,foo1在asm()里首先声明,所以是%0,foo2紧接着所以是%1。"g"表示是一个整型,前面有"="号说明这是一个作为输出的变量(也就是被写的),没有"="号就说明是作为输入的变量。别的被支持的类型还有"r"(寄存器变量),"m"(内存变量),"f"(浮点变量)等等,更多的表示可以参考gcc manual 20.7.1 。
2.3.避免寄存器冲突
如果你在汇编中显式的使用寄存器,编译器会注意不会在上下文中造成冲突,但是有一些指令是不会显式的使用寄存器的,例如cpuid这条指令,它运行以后会改变%eax,%ebx,%ecx,%edx的值,但是这些寄存器不会在代码里出现,因此编译器不会为你避开这个冲突,如果你直接调用这个指令,可能就会造成你的代码core dump!一个笨笨的办法是自己保护寄存器,调用cpuid之前先将四个寄存器push到栈里,运行了cpuid之后将值保存,再pop这四个寄存器。当然这样很影响代码的效率。其实解决的办法很简单,在asm()的第三个冒号后面声明那些需要保护的寄存器就可以了,像这样:
asm("cpuid"
:
:
:"%eax","%ebx","%ecx","%edx");
注意在这里一个"%"号就好了,这样编译器就会小心的避开这些寄存器的冲突。
在c代码中嵌入汇编
1.简介
本文介绍在c代码中嵌入汇编语言的方法,所有的方法仅对gcc(Gnu C Compiler)有效。由于作者是在一台pc上进行的实验,所以例子中如果未加说明,所有的汇编代码均为x86汇编。本文的唯一参考资料就是gcc Manual,其中的5.36小节介绍了在c中嵌入汇编的办法。
2.如何在c中嵌入汇编代码
2.1.最简单的情形
在gcc里有一个asm表达式,用于实现嵌入汇编。就像这样
asm("xor %%eax, %%eax");
这个汇编指令的作用是吧eax寄存器清零,你也许注意到这些代码和我们常见的x86汇编代码有些不同,的确,gcc使用的汇编格式是AT&T格式而不是DOS下常见的Intel格式,它们之间主要区别有:AT&T格式的寄存器使用%标志开头,例如Intel格式中的EAX在这里写作%eax;AT&T格式的目的操作数是后一个而不像Intel格式那样是前一个,比如:
asm("movl %%eax, %%ebx");
是将eax寄存器的值移到ebx。另外还有一些区别,比如内存地址的表示方法等等,详情可以参考DJGPP FAQ里的Coverting between Intel ASM syntax and AT&T syntax。
另外还要注意%号在asm表达式里是特殊字符,所以%eax前面要再加一个%号进行转义,这样就成了"%%eax"这样的寄存器表示方法,如果你用的是Sparc之类的cpu,寄存器使用"r1""r5"之类的表达式,就不需要累赘的%号了。
为了比较易读,多行的汇编代码可以写成这样
asm("xor %%eax, %%eax
movl -20(%%ebp), %%ebx
sub %%ebx, %%eax");
不过在最新的gcc-3系列里一个字符串写了一行以上是会引发一个warning的,让人看了不舒服,这样写就不会了:
asm("xor %%eax, %%eax nt"
"movl -20(%%ebp), %%ebx nt"
"sub %%ebx, %%eax");
n就是换行,t是tab对齐,这下明白了吧 :)
2.2.使用c中定义的变量
先给出一个例子:
int foo;
asm("movl %%eax, %0"
: "=g" (foo));
在asm()中,在冒号分隔符后面声明你的变量,括号中是变量名(foo),"=g"表示这是一个作为输出的整型变量,如果变量是作为输入的话,就要放在第二个括号分隔符后面,象这样:
int foo1,foo2;
asm("movl %1, %%eax nt"
"movl %%eax, %0"
: "=g" (foo1)
: "g" (foo2));
程序是把foo2的内容赋给foo1。从这个例子可以看到,变量在汇编语言里被引用的时候表示符是该变量在asm()里被声明的位置,foo1在asm()里首先声明,所以是%0,foo2紧接着所以是%1。"g"表示是一个整型,前面有"="号说明这是一个作为输出的变量(也就是被写的),没有"="号就说明是作为输入的变量。别的被支持的类型还有"r"(寄存器变量),"m"(内存变量),"f"(浮点变量)等等,更多的表示可以参考gcc manual 20.7.1 。
2.3.避免寄存器冲突
如果你在汇编中显式的使用寄存器,编译器会注意不会在上下文中造成冲突,但是有一些指令是不会显式的使用寄存器的,例如cpuid这条指令,它运行以后会改变%eax,%ebx,%ecx,%edx的值,但是这些寄存器不会在代码里出现,因此编译器不会为你避开这个冲突,如果你直接调用这个指令,可能就会造成你的代码core dump!一个笨笨的办法是自己保护寄存器,调用cpuid之前先将四个寄存器push到栈里,运行了cpuid之后将值保存,再pop这四个寄存器。当然这样很影响代码的效率。其实解决的办法很简单,在asm()的第三个冒号后面声明那些需要保护的寄存器就可以了,像这样:
asm("cpuid"
:
:
:"%eax","%ebx","%ecx","%edx");
注意在这里一个"%"号就好了,这样编译器就会小心的避开这些寄存器的冲突。
|
type "info as" and you will get all information.