Parsing 用汇编语言显示环境变量
我试图通过制作一个显示环境变量的基本程序来理解汇编是如何工作的,比如 C代码:Parsing 用汇编语言显示环境变量,parsing,gcc,assembly,x86-64,Parsing,Gcc,Assembly,X86 64,我试图通过制作一个显示环境变量的基本程序来理解汇编是如何工作的,比如 C代码: int main(int ac, char **av, char **env) { int x; int y; y = -1; while (env[++y]) { x = -1; while (env[y][++x]) { wr
int main(int ac, char **av, char **env)
{
int x;
int y;
y = -1;
while (env[++y])
{
x = -1;
while (env[y][++x])
{
write(1, &(env[y][x]), 1);
}
}
return (0);
}
我用gcc-S(在cygwin64上)编译了它,以了解如何做,并以我自己的方式编写了它(类似但不相同),但它不起作用
$>gcc my_av.s && ./a.exe
HOMEPATH=\Users\hadrien▒2▒p
我的汇编代码:
.file "test.c"
.LC0:
.ascii "\n\0"
.LC1:
.ascii "\033[1;31m.\033[0m\0"
.LC2:
.ascii "\033[1;31m#\033[0m\0"
.LCtest0:
.ascii "\033[1;32mdebug\033[0m\0"
.LCtest1:
.ascii "\033[1;31mdebug\033[0m\0"
.LCtest2:
.ascii "\033[1;34mdebug\033[0m\0"
.def main; .scl 2; .type 32; .endef
main:
/* initialisation du main */
pushq %rbp
movq %rsp, %rbp
subq $48, %rsp
movl %ecx, 16(%rbp) /* int argc */
movq %rdx, 24(%rbp) /* char **argv */
movq %r8, 32(%rbp) /* char **env */
/* saut de ligne */
/* write init */
movl $1, %r8d /* write size */
movl $1, %ecx /* sortie standart */
leaq .LC0(%rip), %rdx
/* write */
call write
/* debut du code */
movl $-1, -8(%rbp) /* y = -1 */
jmp .Loop_1_condition
.Loop_1_body:
movl $-1, -4(%rbp)
jmp .Loop_2_condition
.Loop_2_body:
/* affiche le charactere */
movl $1, %r8d
movl $1, %ecx
call write
.Loop_2_condition:
addl $1, -4(%rbp) /* x = -1 */
movl -8(%rbp), %eax
cltq
addq 32(%rbp), %rax
movq (%rax), %rax
movq %rax, %rdx
movl -4(%rbp), %eax
cltq
addq %rdx, %rax
movq %rax, %rdx
movq (%rax), %rax
cmpq $0, %rax
jne .Loop_2_body
/* saut de ligne */
movl $1, %r8d /* write size */
movl $1, %ecx /* sortie standart */
leaq .LC0(%rip), %rdx
call write
.Loop_1_condition:
addl $1, -8(%rbp) /* ++y */
movl -8(%rbp), %eax
cltq /* passe eax en 64bits */
addq 32(%rbp), %rax
movq (%rax), %rax
cmpq $0, %rax
jne .Loop_1_body
movl $1, %r8d /* write size */
movl $1, %ecx /* sortie standart */
leaq .LC0(%rip), %rdx
call write
/* fin du programme */
movl $0, %eax /* return (0) */
addq $48, %rsp
popq %rbp
ret
.def write; .scl 2; .type 32; .endef
有人能解释一下这个代码有什么问题吗
另外,在试图解决这个问题时,我尝试在cmpq操作中将$0替换为$97,认为它将停止在“a”字符上,但它没有。。。为什么?你有一些问题。在此代码(loop2)中,您有:
addq %rdx, %rax
movq %rax, %rdx
movq (%rax), %rax
cmpq $0, %rax
movq(%rax),%rax
已读取%rax中接下来的8个字符。您只对第一个角色感兴趣。实现这一点的一种方法是将%rax中的最低有效字节与0进行比较。您可以使用cmpb和%al寄存器:
cmpb $0, %al
但最大的问题是理解char**env
是指向char*
数组的指针。首先需要获取数组的基指针,然后用y
索引该基指针。索引看起来有点像basepointer+(y*8)。您需要将y
乘以8,因为每个指针都有8个字节宽。该位置的指针将是特定环境字符串的char*
。然后可以为字符串数组中的每个字符编制索引,直到找到NUL(0)终止字符
我稍微修改了代码,并在我更改的几行上添加了注释:
.file "test.c"
.LC0:
.ascii "\x0a\0"
.LC1:
.ascii "\033[1;31m.\033[0m\0"
.LC2:
.ascii "\033[1;31m#\033[0m\0"
.LCtest0:
.ascii "\033[1;32mdebug\033[0m\0"
.LCtest1:
.ascii "\033[1;31mdebug\033[0m\0"
.LCtest2:
.ascii "\033[1;34mdebug\033[0m\0"
.def main; .scl 2; .type 32; .endef
main:
/* initialisation du main */
pushq %rbp
movq %rsp, %rbp
subq $48, %rsp
movl %ecx, 16(%rbp) /* int argc */
movq %rdx, 24(%rbp) /* char **argv */
movq %r8, 32(%rbp) /* char **env */
/* saut de ligne */
/* write init */
movl $1, %r8d /* write size */
movl $1, %ecx /* sortie standart */
leaq .LC0(%rip), %rdx
/* write */
call write
/* debut du code */
movl $-1, -8(%rbp) /* y = -1 */
jmp .Loop_1_condition
.Loop_1_body:
movl $-1, -4(%rbp)
jmp .Loop_2_condition
.Loop_2_body:
/* affiche le charactere */
movl $1, %r8d
movl $1, %ecx
call write
.Loop_2_condition:
addl $1, -4(%rbp) /* x = -1 */
movl -8(%rbp), %eax /* get y index */
cltq
movq 32(%rbp), %rbx /* get envp (pointer to element 0 of char * array) */
movq (%rbx,%rax,8), %rdx /* get pointer at envp+y*8
pointers are 8 bytes wide */
movl -4(%rbp), %eax /* get x */
cltq
leaq (%rdx, %rax), %rdx /* Get current character's address */
cmpb $0, (%rdx) /* Compare current byte to char 0
using cmpq will compare the next 8 bytes */
jne .Loop_2_body
/* saut de ligne */
movl $1, %r8d /* write size */
movl $1, %ecx /* sortie standart */
leaq .LC0(%rip), %rdx
call write
.Loop_1_condition:
addl $1, -8(%rbp) /* ++y */
movl -8(%rbp), %eax
cltq /* passe eax en 64bits */
movq 32(%rbp), %rbx /* get envp (pointer to element 0 of char * array) */
movq (%rbx,%rax,8), %rax /* get pointer at envp+y*8
pointers are 8 bytes wide */
cmpq $0, %rax /* Compare to NULL ptr */
jne .Loop_1_body
movl $1, %r8d /* write size */
movl $1, %ecx /* sortie standart */
leaq .LC0(%rip), %rdx
call write
/* fin du programme */
movl $0, %eax /* return (0) */
addq $48, %rsp
popq %rbp
ret
.def write; .scl 2; .type 32; .endef
在汇编代码中使用
y
偏移env
的方式看起来不正确。char*
大于一个字节。此外,使用as或gcc组装时,环境也不同。Gcc在程序序言中添加了“C-interface”。请参见Michael>yep您是对的。。。即使使用简单的循环env[y],我也没有得到好的变量数。。。turboscrew>是的,gcc不会让我编译,除非我有主标签,我会看看你的链接谢谢!感谢您花时间更正我的代码!你解决了问题,并解释了问题所在和原因。。。完美的我爱你如果我在解析一个int数组而不是char数组,我会把这个:leaq(%rdx,%rax),%rdx改为:leaq(%rdx,%rax,4),%rdx?@Hadrien:另一个观察结果。您似乎注意到了cltq
指令。此符号扩展(EAX)到完整的64位RAX寄存器中。之所以这样做是因为您将x和y声明为有符号整数。如果您让他们取消签名,生成的代码就不需要cltq
。由于这种情况下的数组索引始终为正,因此可以避免使用cltq
。当您mov
将值放入32位寄存器(例如EAX)时,默认情况下,64位寄存器(RAX)的高32位将自动归零。感谢您提供此详细信息!但在我的脑海里还不是很清楚。我将寻找更多的文档来了解内存是如何工作的,以及位之间的顺序。不过,谢谢你的帮助和时间!