以下宏可以执行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, %%raxn"
"movq %1, %%rdin"
"movq %2, %%rsin"
"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 %dn", fs0.st_size);
struct stat fs1; lstat( "a.out", &fs1); printf("nbytes %dn", 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, %%raxn"
"movq %1, %%rdin"
"movq %2, %%rsin"
"syscall"
:"=m"(ret)
:"m"(_rax), "m"(_path), "m"(_fs)
:"rax", "rdi", "rsi"
);
printf("ret %dn", ret);
}
更新了以下@PeterOrders@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 = %zdn", p, ret, fs.st_size);
ret = m_lstat(p, &fs);
printf("m_lstat: %s: ret = %ld, size = %zdn", p, ret, fs.st_size);
return 0;
}
p.s.如果出于某些原因,您想使用宏,而不是内联函数,则应该使用另一种语法:
#define m_lstat(_path, _fs)
({
long _rax = 6;
asm volatile (
"syscall"
: "+a" (_rax)
: "D" (_path), "S" (_fs)
: "rcx", "r11", "memory"
);
_rax;
})
如果删除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();
(返回打印(做准备
.LC0:
.string "test.txt"
.LC1:
.string "ret %dn"
(...)
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 %dn"
mov eax, 0 // %eax = 0 // ?
call printf
因此,您可以在ret
(mov DWORD PTR [rbp-28], eax
(中获得返回值,正如您所说,返回值在%rax
中。因此,您应该能够像访问任何正常变量一样访问ret
。
PS。希望您不要介意intel语法与%reg
混合,%是表示寄存器与变量的对立。我知道不会有rax
变量,但为了让它更可读,我使用了这个装饰。