Aan*_*mia 1 c gcc nasm inline-assembly
如何在内联汇编gcc中读取stdin并写入stdout,就像我们在NASM中这样做:
_start:
mov ecx, buffer ;buffer is a data word initialised 0h in section .data
mov edx, 03
mov eax, 03 ;read
mov ebx, 00 ;stdin
int 0x80
;Output the number entered
mov eax, 04 ;write
mov ebx, 01 ;stdout
int 0x80
Run Code Online (Sandbox Code Playgroud)
我尝试从内联汇编中的stdin读取,然后将输入分配给x:
#include<stdio.h>
int x;
int main()
{
asm(" movl $5, %%edx \n\t" "
movl $0, %%ebx \n\t" "
movl $3, %%eax \n\t" "
int $0x80 \n\t "
mov %%ecx,x"
::: "%eax", "%ebx", "%ecx", "%edx");
printf("%d",x);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但是它没有这样做.
此链接包含一个只能打印一个字符到stdout的代码.
这段代码完全基于我对linux引用的阅读.我不是在linux上,所以我无法测试它,但它应该非常接近.我会使用重定向测试它:a.out <foo.txt
#include <stdio.h>
#define SYS_READ 3
int main()
{
char buff[10]; /* Declare a buff to hold the returned string. */
ssize_t charsread; /* The number of characters returned. */
/* Use constraints to move buffer size into edx, stdin handle number
into ebx, address of buff into ecx. Also, "0" means this value
goes into the same place as parameter 0 (charsread). So eax will
hold SYS_READ (3) on input, and charsread on output. Lastly, you
MUST use the "memory" clobber since you are changing the contents
of buff without any of the constraints saying that you are.
This is a much better approach than doing the "mov" statements
inside the asm. For one thing, since gcc will be moving the
values into the registers, it can RE-USE them if you make a
second call to read more chars. */
asm volatile("int $0x80" /* Call the syscall interrupt. */
: "=a" (charsread)
: "0" (SYS_READ), "b" (STDIN_FILENO), "c" (buff), "d" (sizeof(buff))
: "memory", "cc");
printf("%d: %s", (int)charsread, buff);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
回应Aanchal Dalmia的评论如下:
1)正如蒂莫西在下面所说,即使你没有使用返回值,你也必须让gcc知道正在修改ax寄存器.换句话说,删除"= a"(charsread)是不安全的,即使它似乎有效.
2)我很惊讶你的观察,除非buff是全局的,否则这段代码不起作用.现在我有一个linux安装程序,我能够重现错误,我怀疑我知道这个问题.我敢打赌你在使用int 0x80x64系统.这不是你应该如何调用64位内核.
这是一些替代代码,显示如何在x64中执行此调用.请注意,上面的示例更改了函数编号和寄存器(请参阅http://blog.rchapman.org/post/36801038863/linux-system-call-table-for-x86-64):
#include <stdio.h>
#define SYS_READ 0
#define STDIN_FILENO 0
int main()
{
char buff[10]; /* Declare a buff to hold the returned string. */
ssize_t charsread; /* The number of characters returned. */
/* Use constraints to move buffer size into rdx, stdin handle number
into rdi, address of buff into rsi. Also, "0" means this value
goes into the same place as parameter 0 (charsread). So eax will
hold SYS_READ on input, and charsread on output. Lastly, I
use the "memory" clobber since I am changing the contents
of buff without any of the constraints saying that I am.
This is a much better approach than doing the "mov" statements
inside the asm. For one thing, since gcc will be moving the
values into the registers, it can RE-USE them if you make a
second call to read more chars. */
asm volatile("syscall" /* Make the syscall. */
: "=a" (charsread)
: "0" (SYS_READ), "D" (STDIN_FILENO), "S" (buff), "d" (sizeof(buff))
: "rcx", "r11", "memory", "cc");
printf("%d: %s", (int)charsread, buff);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这将需要一个比我更好的Linux专家来解释为什么int 0x80on x64不能用于堆栈变量.但是使用syscall确实有效,并且在x64上syscall比int更快.
编辑:有人向我指出,内核在系统调用期间破坏了 rcx和r11.如果不考虑这种情况可能会导致各种问题,所以我已将它们添加到clobber列表中.
| 归档时间: |
|
| 查看次数: |
1550 次 |
| 最近记录: |