printf 用の独自のコードを作成しました。64 ビット マシンを使用しています。ポインターアドレスを印刷しようとしています。何らかの理由で、下位 32 ビット アドレスしか取得できません。完全な住所を取得できない理由を教えていただけますか? これまでの私の調査結果。
Breakpoint 1, kprintf (fmt=0xffffffff00201687 "%p") at sys/main.c:249
249 write_string(0x1F,"0x");
(gdb) p /x addr
$1 = 0xffffffff002050f4
これは私の対応するコードです。
247 case 'p': addr = va_arg(arg_p, uint64_t); // Print Address of the pointer
248 //addr = (uint64_t) v;
249 write_string(0x1F,"0x");
250 write_string(0x1F,convert(addr,16));
251 break;
奇妙なことに、convert 関数の引数が実際に %ediレジスタを介して渡されることがわかりました。これが 32 ビット値を取得している理由です。しかし、なぜ %rdi レジスタに渡されないのか疑問に思っています。これは私の objdump / 逆アセンブリです
658 ffffffff00200a34: 48 89 44 24 08 mov %rax,0x8(%rsp)
659 ffffffff00200a39: be 0a 00 00 00 mov $0xa,%esi
660 ffffffff00200a3e: 8b 39 mov (%rcx),%edi
661 ffffffff00200a40: e8 c3 01 00 00 callq ffffffff00200c08 <convert>
これは、convert 関数で引数を受け取る方法です。
13 char *convert(uint64_t num, int base)
14 {
誰かがここで問題を教えてもらえますか?
編集:コードを追加する
int kprintf(char *fmt,...){
char *p;
uint64_t addr;
int i; // integer argument
char *s; // string argument
va_list arg_p; // pointer to the variable argument list
va_start(arg_p, fmt);
for(p=fmt; *p ; p++){
if(*p != '%'){
write_char(0x1F,*p);
continue;
}
switch(*++p){
case 'p': addr = va_arg(arg_p, uint64_t); // Print Address of the pointer
//addr = (uint64_t) v;
write_string(0x1F,"0x");
write_string(0x1F,convert(addr,16));
break;
}
私のva_list
1 #define va_start(v,l) __builtin_va_start(v,l)
2 #define va_arg(v,l) __builtin_va_arg(v,l)
3 #define va_end(v) __builtin_va_end(v)
4 #define va_copy(d,s) __builtin_va_copy(d,s)
5 typedef __builtin_va_list va_list;
次のようにkrpintfを呼び出しています
kprintf("%p",(uint64_t)&i);
最後に、私の変換機能は
13 char *convert(uint64_t num, int base)
14 {
15 static char buf[65];
16 char *ptr;
17
18 ptr=&buf[sizeof(buf)-1];
19 *ptr='\0';
20 do
21 {
22 *--ptr="0123456789abcdef"[num%base];
23 num/=base;
24 }while(num!=0);
25 return(ptr);
26 }