以下宏可以执行lstat
系统调用。
#include <stdint.h>
#define m_lstat(PATH, FS){ \
long _rax = 6; /*sys_newlstat*/ \
uint8_t* _path = PATH; \
struct stat* _fs = FS; \
asm volatile( \
"movq %0, %%rax\n" \
"movq %1, %%rdi\n" \
"movq %2, %%rsi\n" \
"syscall" \
: \
:"m"(_rax), "m"(_path), "m"(_fs) \
:"rax", "rdi", "rsi" \
); \
}
可以像glibc包装器lstat
那样调用它:
#include <sys/stat.h>
#include <stdio.h>
int main(){
struct stat fs0; m_lstat("a.out", &fs0); printf("nbytes %d\n", fs0.st_size);
struct stat fs1; lstat( "a.out", &fs1); printf("nbytes %d\n", fs1.st_size);
}
但是,如果我想访问返回值怎么办?我认为它已写入rax
,但我不知道如何从C代码中检索它...
例如,以下操作不是:
#define m_lstat(PATH, FS){ \
long _rax = 6; /*sys_newlstat*/ \
u8* _path = PATH; \
struct stat* _fs = FS; \
int ret; \
asm volatile( \
"movq %0, %%rax\n" \
"movq %1, %%rdi\n" \
"movq %2, %%rsi\n" \
"syscall" \
:"=m"(ret) \
:"m"(_rax), "m"(_path), "m"(_fs) \
:"rax", "rdi", "rsi" \
); \
printf("ret %d\n", ret); \
}
在@PeterCordes @MichaelPetch评论之后更新
只需使用适当的约束
inline long m_lstat(char *_path, struct stat *_fs)
{
long _rax = 6;
asm volatile(
"syscall"
: "+a" (_rax)
: "D" (_path), "S" (_fs)
: "rcx", "r11", /* used by syscall */
"memory" /* barrier for _path and _fs */
);
return _rax;
}
此代码
struct stat s;
char foo[] = "foo";
long test()
{
return m_lstat(foo, &s);
}
产生
test:
movl $6, %eax
leaq foo(%rip), %rdi
leaq s(%rip), %rsi
#APP
# 10 "m_lst.c" 1
syscall
# 0 "" 2
#NO_APP
ret
我使用此代码进行测试,一切正常
int main(int argc, char **argv)
{
struct stat fs;
long ret;
char *p = argv[ argc >= 2 ];
ret = lstat(p, &fs);
printf("lstat: %s: ret = %ld, size = %zd\n", p, ret, fs.st_size);
ret = m_lstat(p, &fs);
printf("m_lstat: %s: ret = %ld, size = %zd\n", p, ret, fs.st_size);
return 0;
}
如果删除printf();
呼叫,则会收到以下消息:
.LC0:
.string "test.txt"
main:
push rbp
mov rbp, rsp
sub rsp, 56
.LBB2: // m_lstats
mov QWORD PTR [rbp-8], 6 // _rax = 6;
mov QWORD PTR [rbp-16], OFFSET FLAT:.LC0 // _path = PATH;
lea rax, [rbp-176] // _fs = FS;
mov QWORD PTR [rbp-24], rax
mov rax, QWORD PTR [rbp-8] // %rax = _rax
mov rdx, QWORD PTR [rbp-16] // %rdx = _path
mov rsi, QWORD PTR [rbp-24] // %rsi = _fs
mov rdi, rdx // %rdi = _path
syscall // call
mov DWORD PTR [rbp-28], eax // ret = %eax (low %rax)
.LBE2: // back to main
mov eax, 0 // return 0; // @ main()
leave
ret
其余所有只是准备printf();
(返回printf)
.LC0:
.string "test.txt"
.LC1:
.string "ret %d\n"
(...)
syscall // call
mov DWORD PTR [rbp-28], eax // (*)ret = %eax (low %rax)
mov eax, DWORD PTR [rbp-28] // %esi = &ret
mov esi, eax //
mov edi, OFFSET FLAT:.LC1 // %edi = &"ret %d\n"
mov eax, 0 // %eax = 0 // ?
call printf
所以您确实在ret
(mov DWORD PTR [rbp-28], eax
)中得到了返回值,正如您所说的,返回值在%rax
中。因此,您应该能够像访问任何普通变量一样访问ret
。
PS。希望您不要介意与%reg
混合使用的intel语法,%表示与变量相反的寄存器。我知道不会有rax
变量,但是为了使它更具可读性,我使用了这种装饰。