一位同事曾告诉我,当Linux上的所有内容都无法调试时,最后一个选项是使用strace.
我试图学习这个奇怪工具背后的科学,但我不是系统管理大师,我没有真正得到结果.
所以,
简而言之,简单来说,这些东西是如何工作的?
以下链接解释了UNIX(BSD风格)和Linux的x86-32系统调用约定:
但是UNIX和Linux上的x86-64系统调用约定是什么?
我读了LKD 1中的一些段落, 我无法理解下面的内容:
从用户空间访问系统调用
通常,C库提供对系统调用的支持.用户应用程序可以从标准头中提取函数原型并与C库链接以使用您的系统调用(或者库例程,而该库例程又使用您的系统调用).但是,如果您刚刚编写了系统调用,那么glibc已经支持它是值得怀疑的!
值得庆幸的是,Linux提供了一组用于包装系统调用访问的宏.它设置寄存器内容并发出陷阱指令.这些宏被命名,其中介于0和6之间.该数字对应于传递给系统调用的参数数量,因为宏需要知道预期的参数数量,从而推入寄存器.例如,考虑系统调用,定义为
_syscalln()nopen()Run Code Online (Sandbox Code Playgroud)long open(const char *filename, int flags, int mode)在没有显式库支持的情况下使用此系统调用的syscall宏将是
Run Code Online (Sandbox Code Playgroud)#define __NR_open 5 _syscall3(long, open, const char *, filename, int, flags, int, mode)然后,应用程序可以简单地调用
open().对于每个宏,有2 + 2×n个参数.第一个参数对应于系统调用的返回类型.第二个是系统调用的名称.接下来是系统调用顺序的每个参数的类型和名称.的
__NR_open定义是在<asm/unistd.h>; 它是系统呼叫号码.的_syscall3宏扩展到与联汇编C函数; 程序集执行上一节中讨论的步骤,将系统调用号和参数推送到正确的寄存器中,并发出软件中断以陷入内核.将此宏放在应用程序中是使用open()系统调用所需的全部内容.让我们编写宏来使用我们精彩的新
foo()系统调用,然后编写一些测试代码来展示我们的努力.Run Code Online (Sandbox Code Playgroud)#define __NR_foo 283 __syscall0(long, foo) int main () { long stack_size; stack_size = foo (); printf ("The kernel stack size is %ld\n", stack_size); return 0; }
是什么 …
这是寄存器加载代码列表:
a eax
b ebx
c ecx
d edx
S esi
D edi
I常数值(0到31)
q,r动态分配寄存器(见下文)
g eax,ebx,ecx,edx或内存中
的变量a eax和edx合并为64位整数(使用long longs)
但这是intel i386的注册限制.我的问题是我可以在哪里找到intel x86_64系统的寄存器限制,例如:
?%r10
?%r8
?%的RDX
等等.
有谁知道在汇编语言中为Linux系统调用找到汇总表或备忘单的位置?我通过int 0x80指令调用Linux系统调用,我需要不时地引用哪个寄存器包含什么值.
谢谢.
我正在尝试使用内联汇编...我读过这个页面http://www.codeproject.com/KB/cpp/edujini_inline_asm.aspx但我无法理解传递给我的函数的参数.
我正在写一个C写的例子..这是我的函数头:
write2(char *str, int len){
}
Run Code Online (Sandbox Code Playgroud)
这是我的汇编代码:
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
Run Code Online (Sandbox Code Playgroud)
我该怎么做才能将代码传递给C函数...我正在做这样的事情:
write2(char *str, int len){
asm ( "movl 4, %%eax;"
"movl 1, %%ebx;"
"mov %1, %%ecx;"
//"mov %2, %%edx;"
"int 0x80;"
:
: "a" (str), "b" (len)
);
}
Run Code Online (Sandbox Code Playgroud)
那是因为我没有输出变量,所以我该如何处理呢?此外,使用此代码:
global main
main:
mov ebx, 5866 ;PID
mov ecx, …Run Code Online (Sandbox Code Playgroud) 从MS-DOS开始,我知道使用中断的系统调用.在旧论文中,我看到了int 80h在Linux上调用系统函数的参考.由于现在相当长的一段时间,我知道int 80h不赞成使用该syscall指令.但我不能让它在我的32位机器上工作.
该syscall指令仅用于64位平台吗?不是32位Linux使用syscall?
在我的32位Linux(Ubuntu Precise)上,该程序终止于核心转储:
global _start
_start:
mov eax, 4 ; 4 is write
mov ebx, 1 ; 1 is stdout
mov ecx, message ; address of string
mov edx, length ; number of bytes
syscall
mov eax, 1 ; 1 is exit
xor ebx, ebx ; return code 0
syscall
message:
db 10,"Hello, World",10,10
length equ $ - message
Run Code Online (Sandbox Code Playgroud)
我试过sysenter而不是syscall,但它以同样的方式崩溃.
最近我在玩 freebsd 系统调用,我对 i386 部分没有问题,因为它在这里有很好的记录。但是我找不到 x86_64 的相同文档。
我看到人们在 linux 上使用相同的方式,但他们只使用程序集而不是 c。我想在我的例子中,系统调用实际上改变了一些被高优化级别使用的寄存器,所以它给出了不同的行为。
/* for SYS_* constants */
#include <sys/syscall.h>
/* for types like size_t */
#include <unistd.h>
ssize_t sys_write(int fd, const void *data, size_t size){
register long res __asm__("rax");
register long arg0 __asm__("rdi") = fd;
register long arg1 __asm__("rsi") = (long)data;
register long arg2 __asm__("rdx") = size;
__asm__ __volatile__(
"syscall"
: "=r" (res)
: "0" (SYS_write), "r" (arg0), "r" (arg1), "r" (arg2)
: "rcx", "r11", "memory"
); …Run Code Online (Sandbox Code Playgroud) 在 x86 内联汇编中,我可以这样写:
asm ("cpuid"
: "=a" (_eax),
"=b" (_ebx),
"=c" (_ecx),
"=d" (_edx)
: "a" (op));
Run Code Online (Sandbox Code Playgroud)
所以在 matchin 约束中,而不是只写“=r”并让编译器选择寄存器,我可以说我想使用哪个特定的寄存器(=a 例如使用 %eax)
我怎样才能为 ARM 程序集做到这一点?ARM GCC 汇编手册http://www.ethernut.de/en/documents/arm-inline-asm.html指出,例如,我可以将约束“r”用于通用寄存器 R0-R15“w”之一" 对于 VFP 浮点寄存器 S0-S31 之一
但是我怎样才能将一个操作数限制在例如 s1 呢?或特定的通用寄存器?