在C / C使用内联汇编++ [英] Using Inline Assembly in C/C++

查看:138
本文介绍了在C / C使用内联汇编++的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试使用内联汇编...
我读这页 HTTP://www.$c$cproject.com/KB /cpp/edujini_inline_asm.aspx 但我无法理解传递给我的函数的参数。

我正在写一个C写的例子..这是我的函数头:

  write2(的char * str中,INT LEN){
}

这是我的组装code:

 全球write2
write2:
    推EBP
    MOV EBP,ESP
    MOV EAX,4; SYS_WRITE
    MOV EBX,1;标准输出
    MOV ECX,[EBP + 8];字符串的指针
    MOV EDX,[EBP + 12];字符串大小
    INT 0x80的;系统调用
    离开
    RET

什么我必须做传递code和C函数...我在做这样的事情:

  write2(的char * str中,INT LEN){
    ASM(MOVL 4 %% EAX;
          MOVL 1 %% EBX;
          MOV%1 %% ECX;
          //MOV%2 %% EDX;
          INT 0x80的;
           :
           :一(STR),B(LEN)
    );
}

这是因为我没有一个输出变量,所以我怎么处理这个问题?
另外,在该code:

 全球主要
主要:
    MOV EBX,5866; PID
    MOV ECX,9,SIGKILL
    MOV EAX,37; sys_kill
    INT 0x80的;中断
    RET

我怎样才能把那个code内嵌在我的code ..所以我可以要求PID给用户..这样的..
这是我的pre code

 无效killp(INT PID){
    ASM(MOV%1 %% EBX;
          MOV 9 %% ECX;
          MOV 37 %% EAX;
           :
           :A(PID)/ * *可选/
    );
}


解决方案

好吧,你不说具体的,而是由你的帖子,看来就像你使用gcc和约束语法的内联汇编(其他C编译器有很不同的内联语法)。这就是说,你可能需要使用AT&放大器;:T汇编语法,而不是英特尔,因为这就是被用gcc使用

因此​​,与上面说的,让我们看看你的write2功能。首先,你不希望创建一个栈帧,因为gcc会创建一个,所以如果你创建一个在ASM code,你最终会用两帧,事情可能会变得非常混乱。第二,由于GCC是奠定了堆栈帧,则无法访问瓦尔[EBP +偏移]的广告,你不知道它被如何安排。这就是约束条件是 - 你说你要GCC把值(任何寄存器,内存,特定的寄存器),并使用%X中的ASM code什么样的地方。最后,如​​果你在ASM code使用明确的寄存器,你需要列出他们(在输入约束之后)第3节以使gcc知道你在使用它们。否则可能把一些重要的价值在这些寄存器中的一个,你就要揍那个值。

因此​​,与所有这一切,你write2功能如下:

 无效write2(的char * str中,INT LEN){
    __asm​​__挥发性(
        MOVL $ 4 %% EAX;
        MOVL $ 1,EBX %%;
        MOVL%0 %% ECX;
        MOVL%1 %% EDX;
        INT 0x80的$
        ::G(STR),G(LEN)
        :EAX,EBX,ECX,EDX);
}

请注意在AT&安培; T语法 - SRC,DEST而不是DEST,SRC和寄存器名前

现在这会工作,但它的效率低下,因为它含有大量的额外MOVS的。一般情况下,你不应该使用MOV指令或明确寄存器ASM code,因为你多使用约束地说,你想要的东西,让编译器确保他们在那里更好。通过这种方式,优化也许可以摆脱大部分MOVS的,特别是当它内联的函数(如果指定-O3它会做)。方便的是,i386的机型有特定的寄存器约束,这样你就可以做,而不是:

 无效write2(的char * str中,INT LEN){
    __asm​​__挥发性(
        MOVL $ 4 %% EAX;
        MOVL $ 1,EBX %%;
        INT 0x80的$
        ::C(STR)/ * C约束告诉编译器把海峡在ECX * /
           D(LEN)/ * D约束告诉编译器把len个EDX * /
        :EAX,EBX);
}

甚至更好

 无效write2(的char * str中,INT LEN){
    __asm​​__挥发性(INT 0x80的$
        ::一个(4),B(1)中,C(STR),D(LEN));
}

还要注意使用挥发性这是需要告诉这个不能消除死即使它的输出(其中有没有)是编译器不使用。

修改

最后要注意 - 这个功能是做一个写系统调用,这并在eax中返回一个值 - 写入的字节数或错误code。所以,你可以得到与输出约束:

  INT write2(字符* STR,INT LEN){
    __asm​​__(INT $ 0x80的:=一个(LEN):一(4),B(1)中,C(STR),D(LEN));
    返回LEN;
}

通过真实的输出,你可能会或可能不希望挥发 - 没有它可以让编译器死区code消除写,如果不使用返回值。但你总是检查错误的返回值吧?

I'm trying to use inline assembly... I read this page http://www.codeproject.com/KB/cpp/edujini_inline_asm.aspx but I can't understand the parameters passing to my function.

I'm writing a C write example.. this is my function header:

write2(char *str, int len){
}

And this is my assembly code:

global write2
write2:
    push ebp
    mov ebp, esp
    mov eax, 4      ;sys_write
    mov ebx, 1      ;stdout
    mov ecx, [ebp+8]    ;string pointer
    mov edx, [ebp+12]   ;string size
    int 0x80        ;syscall
    leave
    ret

What do I have to do pass that code to the C function... I'm doing something like this:

write2(char *str, int len){
    asm ( "movl 4, %%eax;"
          "movl 1, %%ebx;"
          "mov %1, %%ecx;"
          //"mov %2, %%edx;"
          "int 0x80;"
           :
           : "a" (str), "b" (len)
    );
}

That's because I don't have an output variable, so how do I handle that? Also, with this code:

global main
main:
    mov ebx, 5866       ;PID
    mov ecx, 9      ;SIGKILL
    mov eax, 37     ;sys_kill
    int 0x80        ;interruption
    ret 

How can I put that code inline in my code.. so I can ask for the pid to the user.. like this.. This is my precode

void killp(int pid){
    asm ( "mov %1, %%ebx;"
          "mov 9, %%ecx;"
          "mov 37, %%eax;"
           :
           : "a" (pid)         /* optional */
    );
}

解决方案

Well, you don't say specifically, but by your post, it appears like you're using gcc and its inline asm with constraints syntax (other C compilers have very different inline syntax). That said, you probably need to use AT&T assembler syntax rather than Intel, as that's what gets used with gcc.

So with the above said, lets look at your write2 function. First, you don't want to create a stack frame, as gcc will create one, so if you create one in the asm code, you'll end up with two frames, and things will probably get very confused. Second, since gcc is laying out the stack frame, you can't access vars with "[ebp + offset]" ad you don't know how its being laid out. That's what the constraints are for -- you say what kind of place you want gcc to put the value (any register, memory, specific register) and the use "%X" in the asm code. Finally, if you use explicit registers in the asm code, you need to list them in the 3rd section (after the input constraints) so gcc knows you are using them. Otherwise it might put some important value in one of those registers, and you'd clobber that value.

So with all that, your write2 function looks like:

void write2(char *str, int len) {
    __asm__ volatile (
        "movl $4, %%eax;"
        "movl $1, %%ebx;"
        "movl %0, %%ecx;"
        "movl %1, %%edx;"
        "int $0x80"
        :: "g" (str), "g" (len)
        : "eax", "ebx", "ecx", "edx");
}

Note the AT&T syntax -- src, dest rather than dest, src and % before the register name.

Now this will work, but its inefficient as it will contain lots of extra movs. In general, you should NEVER use mov instructions or explicit registers in asm code, as you're much better off using constraints to say where you want things and let the compiler ensure that they're there. That way, the optimizer can probably get rid of most of the movs, particularly if it inlines the function (which it will do if you specify -O3). Conveniently, the i386 machine model has constraints for specific registers, so you can instead do:

void write2(char *str, int len) {
    __asm__ volatile (
        "movl $4, %%eax;"
        "movl $1, %%ebx;"
        "int $0x80"
        :: "c" (str), /* c constraint tells the compiler to put str in ecx */
           "d" (len)  /* d constraint tells the compiler to put len in edx */
        : "eax", "ebx");
}

or even better

void write2(char *str, int len) {
    __asm__ volatile ("int $0x80"
        :: "a" (4), "b" (1), "c" (str), "d" (len));
}

Note also the use of volatile which is needed to tell the compiler that this can't be eliminated as dead even though its outputs (of which there are none) are not used.

edit

One final note -- this function is doing a write system call, which does return a value in eax -- either the number of bytes written or an error code. So you can get that with an output constraint:

int write2(char *str, int len) {
    __asm__ ("int $0x80" : "=a" (len) : "a" (4), "b" (1), "c" (str), "d" (len));
    return len;
}

With a real output, you may or may not want the volatile -- not having it will allow the compiler to dead-code eliminate the write if the return value is not used. But you always check the return value for errors, right?

这篇关于在C / C使用内联汇编++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆