来自GCC内联程序集中的系统调用

来自GCC内联程序集中的系统调用,c,linux,gcc,inline-assembly,system-calls,C,Linux,Gcc,Inline Assembly,System Calls,可以从内联汇编块中使用系统调用写入单个字符吗?如果是,怎么做?它应该看起来像这样的“某物”: __asm__ __volatile__ ( " movl $1, %%edx \n\t" " movl $80, %%ecx \n\t" " movl $0, %%ebx \n\t" " mo

可以从内联汇编块中使用系统调用写入单个字符吗?如果是,怎么做?它应该看起来像这样的“某物”:

__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"
                    );
$80在ascii中是“p”,但不返回任何内容


非常感谢您的任何建议

IIRC,在你的例子中有两件事是错误的。 首先,您正在使用mov$0、%ebx向stdin写信 第二,write将指针作为它的第二个参数,因此要写入一个字符,需要将该字符存储在内存中的某个位置,不能将该值直接写入%ecx

例:

我只在Linux中做过纯asm,从未使用gcc内联,您不能将数据放到程序集的中间,因此我不确定如何使用内联程序集获取指针

编辑:我想我刚刚记得怎么做了。您可以将“p”推到堆栈上并使用%esp

pushw $80
movl %%esp, %%ecx
... int $0x80 ...
addl $2, %%esp
差不多


char p = 'P';

int main()
{
__asm__ __volatile__
                    (
                     " movl $1,  %%edx \n\t"
                     " leal p , %%ecx \n\t"
                     " movl $0,  %%ebx \n\t"
                     " movl $4,  %%eax \n\t"
                     " int $0x80       \n\t"
                     ::: "%eax", "%ebx", "%ecx", "%edx"
                    );
}
Add:注意,我使用了
lea
将字符的有效地址加载到
ecx
寄存器中;对于
ebx
的值,我尝试了$0和$1,但它似乎仍然有效

避免使用外部字符

int main()
{
__asm__ __volatile__
                    (
                     " movl $1,  %%edx \n\t"
                     " subl $4, %%esp \n\t"
                     " movl $80, (%%esp)\n\t"
                     " movl %%esp, %%ecx \n\t"
                     " movl $1,  %%ebx \n\t"
                     " movl $4,  %%eax \n\t"
                     " int $0x80       \n\t"
                     " addl $4, %%esp\n\t"
                     ::: "%eax", "%ebx", "%ecx", "%edx"
                    );
}

注意:它之所以能工作,是因为英特尔处理器的持久性D

您可以使用特定于体系结构的约束直接将参数放置在特定寄存器中,而无需内联程序集中的
movl
指令。此外,您还可以使用
&
运算符获取字符的地址:

#包括
无效系统计算机(字符c){
//写入(int-fd,const-void*buf,size\u-t-count);
int ret;
asm易失性(“int$0x80”
:“=a”(ret)//输出
:“a”(系统写入),“b”(1),“c”(&c),“d”(1)//输入
:“内存”);//碰撞
}
内部主(空){
系统计算机(‘P’);
系统计算机('\n');
}
(编者按:需要使用
“内存”
clobber,或者以其他方式告诉编译器已读取
&c
指向的内存。)


(在这种情况下,
=a(ret)
需要指示系统调用阻塞器EAX。我们不能将EAX列为阻塞器,因为我们需要一个输入操作数来使用该寄存器。
“a”
约束类似于
“r”
,但只能选择AL/AX/EAX/RAX。)

您还可以返回系统调用返回的写入字节数,并使用
“0”
作为约束再次指示EAX:

请注意,出现错误时,系统调用返回值将是
-errno
代码,如
-EBADF
(错误文件描述符)或
-EFAULT
(错误指针)

正常的libc系统调用包装函数检查unsigned
eax>-4096UL
的返回值,并设置errno+return
-1


还请注意,需要使用
-m32
进行编译:64位
系统调用
ABI使用不同的呼叫号码(和寄存器),但此asm对调用32位ABI的缓慢方式进行硬编码,
int$0x80


在64位模式下编译将得到
sys/syscall.h
来定义带有64位调用号的
sys\u write
,这将破坏此代码。即使使用了正确的数字,64位堆栈地址也是如此。-不要这样做。

好的-我已经为您添加了
linux
标签我相信这是重复的:如果您认为我犯了错误,请告诉我。干杯。在C语言中,我用
char*p='p'做“相同的”;写入(1,&p,1)
,所以stdout是1char*p='p'应该是char p='p',我想。
write()
const void*buf
作为它的第二个参数刚刚计算出来,你当然是对的!应该是
charp
thx!我只是想知道如何使用
push
。。使用
push
pushb
有什么区别?当我做完的时候,我必须把它们打开吗?啊。我还不太擅长组装,所以我基本上对lea之类的东西一无所知。。另外,0和1分别是标准差和标准差。IIRC当然可以使用堆栈;gcc生成的代码使用它之前准备的ebp;我们可以暂时坚持使用esp;我已经修改了答案,看吧。太棒了!!也可以使用
push
和stackpointer来完成吗?由于建议使用push,您可以更好地使用我的代码(但是pushb不存在,而且无论如何它会“取消对齐”堆栈…):删除subl$4,%esp,而不是
movl$80,(%esp)
put
pushl$80
;其余的都一样,嗯,现在看到你的评论,;是的,如前所述,您可以使用pushl并避免手动减少堆栈;esp是堆栈指针;要使用基/帧指针ebp或如何调用它,应保留C对局部变量使用的它的先前值;。。。因此,毕竟它不是那么有用,在这种情况下,ESP是第一示例中的简单例子,我认为它是一个bug。一个问题是
int$0x80
改变了EAX,因为它包含一个返回值。您需要确保具有某种输出约束,否则优化器可能会假定EAX包含扩展程序集模板中的SYS_write值。您的第二个代码示例做得很好。非常好,谢谢!我想在第一个版本的clobber列表中添加“%eax”就足够了?(我确实想包括一个没有输出的版本。)不要认为am EAX clobber会在那里工作,因为编译器可能会使用
“a”
假设它与仅输入约束冲突。我怀疑会出现某种错误。你是对的。不久前有一个针对gcc的bug,他们建议使用一个虚拟输出变量。(有人建议允许在输入操作数中使用
&
,但没有得到热烈的欢迎。)在第一个版本中处理EAX clobber问题的最佳方法是创建一个伪输出变量。如果使用优化进行编译,优化器将能够
int main()
{
__asm__ __volatile__
                    (
                     " movl $1,  %%edx \n\t"
                     " subl $4, %%esp \n\t"
                     " movl $80, (%%esp)\n\t"
                     " movl %%esp, %%ecx \n\t"
                     " movl $1,  %%ebx \n\t"
                     " movl $4,  %%eax \n\t"
                     " int $0x80       \n\t"
                     " addl $4, %%esp\n\t"
                     ::: "%eax", "%ebx", "%ecx", "%edx"
                    );
}
$ cc -m32 sys_putc.c && ./a.out
P
int sys_putc(char c) {
    int ret;
    asm volatile("int $0x80" : "=a"(ret) : "0"(SYS_write), "b"(1), "c"(&c), "d"(1) : "memory");
    return ret;
}