Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Parsing 用汇编语言显示环境变量_Parsing_Gcc_Assembly_X86 64 - Fatal编程技术网

Parsing 用汇编语言显示环境变量

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

我试图通过制作一个显示环境变量的基本程序来理解汇编是如何工作的,比如

C代码:

    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位将自动归零。感谢您提供此详细信息!但在我的脑海里还不是很清楚。我将寻找更多的文档来了解内存是如何工作的,以及位之间的顺序。不过,谢谢你的帮助和时间!