汇编 int linux,在GNU C内联汇编中编写Linux int 80h系统调用包...

好吧,你没有特别说,但是你的帖子看起来好像你正在使用gcc及其内联asm和约束语法(其他C编译器具有非常不同的内联语法).也就是说,您可能需要使用AT& T汇编语法而不是英特尔,因为这是与gcc一起使用的.

所以用上面说过,让我们来看看你的write2函数.首先,你不想创建一个堆栈框架,因为gcc会创建一个,所以如果你在asm代码中创建一个,你最终会得到两个框架,事情可能会变得很困惑.其次,由于gcc正在布置堆栈帧,因此您无法访问带有“[ebp offset]”的变量,因为您不知道它是如何布局的.

这就是约束的含义 – 你说你希望gcc在什么样的地方放置值(任何寄存器,内存,特定寄存器)和在asm代码中使用“%X”.最后,如果在asm代码中使用显式寄存器,则需要在第3部分中列出它们(在输入约束之后),因此gcc知道您正在使用它们.否则它可能会在其中一个寄存器中放入一些重要的值,你就会破坏这个值.

您还需要告诉编译器内联asm将或可能读取或写入由输入操作数指向的内存;这并不暗示.

所以,你的write2函数看起来像:

void write2(char *str, int len) {

__asm__ volatile (

"movl $4, %%eax;" // SYS_write

"movl $1, %%ebx;" // file descriptor = stdout_fd

"movl %0, %%ecx;"

"movl %1, %%edx;"

"int $0x80"

:: "g" (str), "g" (len) // input values we MOV from

: "eax", "ebx", "ecx", "edx", // registers we destroy

"memory" // memory has to be in sync so we can read it

);

}

注意AT& T语法 – 在寄存器名称之前的src,dest而不是dest,src和%.

现在这将有效,但效率低,因为它将包含许多额外的mov.一般情况下,你不应该在asm代码中使用mov指令或显式寄存器,因为你最好使用约束来说出你想要的东西,并让编译器确保它们在那里.这样,优化器可能可以摆脱大多数mov,特别是如果它内联函数(如果你指定-O3将会这样做).方便的是,i386机器模型具有特定寄存器的约束,因此您可以改为:

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", "memory");

}

甚至更好

// UNSAFE: destroys EAX (with return value) without telling the compiler

void write2(char *str, int len) {

__asm__ volatile ("int $0x80"

:: "a" (4), "b" (1), "c" (str), "d" (len)

: "memory");

}

还要注意使用volatile来告诉编译器即使没有使用它的输出(其中没有输出),也不能将其作为死区消除. (没有输出操作数的asm已经隐式挥发,但是当真正的目的不是为了计算某些东西时,使其显式不会受到伤害;它是像系统调用那样的副作用.)

编辑

最后要注意的是 – 这个函数正在执行一个写系统调用,它会在eax中返回一个值 – 写入的字节数或错误代码.所以你可以通过输出约束得到它:

int write2(const char *str, int len) {

__asm__ volatile ("int $0x80"

: "=a" (len)

: "a" (4), "b" (1), "c" (str), "d" (len),

"m"( *(const char (*)[])str ) // "dummy" input instead of memory clobber

);

return len;

}

所有系统调用都在EAX中返回. -4095到-1(含)的值是负的errno代码,其他值是非错误的. (这适用于所有Linux系统调用).

如果你正在编写一个通用的系统调用包装器,你可能需要一个“内存”代码,因为不同的系统调用有不同的指针操作数,可能是输入或输出.有关断开示例的示例,请参阅https://godbolt.org/z/GOXBue;有关虚拟内存输入/输出的详细信息,请参阅this answer.

使用此输出操作数,您需要显式volatile – 每次asm语句在源中“运行”时,只需一次写入系统调用.否则,允许编译器假定它仅存在以计算其返回值,并且可以消除具有相同输入的重复调用而不是写入多行. (如果没有检查返回值,则完全删除它.)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值