鱼C论坛

 找回密码
 立即注册
查看: 1485|回复: 8

[已解决]汇编代码求解

[复制链接]
发表于 2023-7-13 11:24:34 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 HWitty 于 2023-7-13 11:27 编辑

#include<stdio.h>
int main()
{
        int n = 1;
        scanf("%d",&n);
        switch(n)
        {
                略。
        }
}
**********************************************以下为汇编(程序为debug版无优化)
push ebp
mov ebp,esp
sub esp,8                    ->   源程序中只有一个参数,为啥此处不esp-4,而是esp-8 ?????        
mov dword ptr [ebp-8],1
lea eax,[ebp-8]
push eax
push offset unk_417160
call sub_401130
add esp,8
mov ecx,[ebp-8]                ->   为啥不直接用【ebp-8】地址,而用ecx转到[ebp-4],再cmp。
mov [ebp-4],ecx
cmp dword ptr [ebp-4],1
jz.........

最佳答案
2023-7-13 12:34:39
这段代码是一个简单的 C 语言程序,用于根据用户输入的值 n 执行不同的逻辑。以下是代码的详细解释:

首先,在 main 函数中,一个整型变量 n 被初始化为 1,并使用 scanf 函数从用户输入中读取 n 的新值。

然后,程序进入一个 switch 语句,根据 n 的值执行不同的逻辑。对于每个 case 分支,都有相应的打印语句和 break 语句用于跳出 switch 语句。

现在来分析汇编代码片段:
push ebp                     ; 保存旧的基址指针到栈中
mov ebp, esp                 ; 设置新的基址指针为当前栈顶
sub esp, 8                   ; 在堆栈上分配 8 字节的空间(用于局部变量和临时数据)

mov dword ptr [ebp-8], 1     ; 将值 1 存储到 ebp-8(局部变量 n)中
lea eax, [ebp-8]             ; 计算局部变量 n 的地址,并将其存储到 eax 寄存器中
push eax                     ; 将局部变量 n 的地址推入栈中(作为函数调用的参数)
push offset unk_417160       ; 推入一个位置未知的常量值作为第二个参数
call sub_401130              ; 调用 sub_401130 函数

add esp, 8                   ; 执行函数调用后,根据调用规约恢复栈指针
mov ecx, [ebp-8]             ; 将局部变量 n 的值加载到 ecx 寄存器中
mov [ebp-4], ecx             ; 将 ecx 寄存器中的值存储回 [ebp-4](用于后续的比较操作)

cmp dword ptr [ebp-4], 1     ; 将 [ebp-4](n 的值)与 1 进行比较
jz short loc_401038          ; 如果相等,则跳转到 loc_401038 代码块
cmp dword ptr [ebp-4], 3     ; 将 [ebp-4](n 的值)与 3 进行比较
jz short loc_401047          ; 如果相等,则跳转到 loc_401047 代码块
jmp short loc_401063         ; 否则,跳转到 loc_401063 代码块

loc_401038:                  ; 标签 loc_401038
push offset aN1              ; 推入字符串 "n==1" 的地址作为参数
call sub_4010F0              ; 调用 sub_4010F0 函数(可能是用于打印字符串)
add esp, 4                   ; 根据调用规约恢复栈指针
jmp short loc_401063         ; 跳转到 loc_401063 代码块

loc_401047:                  ; 标签 loc_401047
push offset aN3              ; 推入字符串 "n==3" 的地址作为参数
call sub_4010F0              ; 调用 sub_4010F0 函数(可能是用于打印字符串)
add esp, 4                   ; 根据调用规约恢复栈指针
jmp short loc_401063         ; 跳转到 loc_401063 代码块

loc_401063:                  ; 标签 loc_401063
xor eax, eax                 ; 将 eax 寄存器清零
mov esp, ebp                 ; 恢复栈指针
pop ebp                      ; 恢复旧的基址指针
retn                         ; 返回

总之,这个程序的功能是根据用户输入的 n 的值执行相应的逻辑,并打印相应的信息。注意,汇编代码中的函数调用和其他细节可能使用了未给出的代码或数据。

关于你提出的两个问题:

Q:sub esp,8                    ->   源程序中只有一个参数,为啥此处不esp-4,而是esp-8 ?????
A:在这段代码中,sub esp, 8 操作是为了在堆栈上分配足够的空间来存储局部变量和临时数据。在大多数情况下,函数调用使用堆栈来传递参数和保存返回地址,所以在函数开始时先给堆栈分配一些额外的空间。
Q:mov ecx,[ebp-8]                ->   为啥不直接用【ebp-8】地址,而用ecx转到[ebp-4],再cmp。
A:关于第二个问题,这段代码是将 [ebp-8] 中的值加载到 ecx 寄存器中,并将其存储到 [ebp-4],而不直接使用 [ebp-8] 的原因可能是为了后续比较操作的方便。通过将值从 [ebp-8] 复制到 [ebp-4],可以方便地与其他值进行比较,而不需要再次访问 [ebp-8]。这样的操作可能是为了简化代码或者遵循特定的编码风格。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-7-13 11:30:03 | 显示全部楼层
本帖最后由 歌者文明清理员 于 2023-7-13 11:31 编辑

在你提供的代码片段中,有一些疑问和注意事项:

  • 关于 sub esp,8:在函数开头,通常会为局部变量分配一些空间。在这个代码片段中,sub esp, 8 分配了 8 字节的空间。这可能是因为编译器需要一些额外的空间来执行其他操作,或者是为栈帧保留的空间。
  • 关于 mov ecx, [ebp-8] 和 mov [ebp-4], ecx:这两个操作是将局部变量 n(位于 [ebp-8])的值复制到 ecx 寄存器中,并将 ecx 中的值复制回 [ebp-4]。这可能是为了方便在后续的操作中使用 ecx 寄存器。
  • 缺少 case 分支:你提供的代码片段中省略了 switch 语句的具体 case 分支。如果你需要更详细的帮助,请提供完整的代码,我将尽力为你解答。


总体而言,我建议对代码进行进一步分析和调试,以便更好地理解程序的逻辑和目的。

详细版:

当进入 main 函数时,以下是代码片段中的汇编指令的详细解释:
push ebp         ; 保存旧的基址指针到栈中
mov ebp, esp     ; 设置新的基址指针为当前栈顶
sub esp, 8       ; 在堆栈上分配 8 字节的空间(用于局部变量和临时数据)

mov dword ptr [ebp-8], 1  ; 将值 1 存储到 ebp-8(局部变量 n)中
lea eax, [ebp-8]          ; 计算局部变量 n 的地址,并将其存储到 eax 寄存器中
push eax                  ; 将局部变量 n 的地址推入栈中(作为函数调用的参数)
push offset unk_417160    ; 推入一个位置未知的常量值作为第二个参数
call sub_401130           ; 调用 sub_401130 函数

add esp, 8                ; 执行函数调用后,根据调用规约恢复栈指针
mov ecx, [ebp-8]          ; 将局部变量 n 的值加载到 ecx 寄存器中
mov [ebp-4], ecx          ; 将 ecx 寄存器中的值存储回 [ebp-4](用于后续的比较操作)

cmp dword ptr [ebp-4], 1  ; 将 [ebp-4](n 的值)与 1 进行比较
jz ...                    ; 如果相等,则跳转到指定的代码块

; 省略其他 case 分支和代码块
这个汇编代码片段首先设置了函数的栈帧,然后将值 1 存储到局部变量 n 中。然后,它调用了一个函数,并使用 lea 指令计算并推入局部变量 n 的地址作为函数调用的参数。

接下来,它将局部变量 n 的值加载到 ecx 寄存器中,并将其存储回另一个局部变量(位于 [ebp-4])。然后,它使用 cmp 指令将这个值与 1 进行比较,根据比较的结果进行条件跳转。

请注意,由于你提供的代码片段省略了部分细节,无法完全了解它的功能和逻辑。如果你需要更详细的解释,请提供完整的代码,我将尽力为你提供帮助。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-13 12:19:38 | 显示全部楼层
歌者文明清理员 发表于 2023-7-13 11:30
在你提供的代码片段中,有一些疑问和注意事项:

完整代码

1

1

2

2
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-13 12:20:26 | 显示全部楼层
网站只支持2m图片上传,太难受了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-13 12:24:25 | 显示全部楼层
HWitty 发表于 2023-7-13 12:20
网站只支持2m图片上传,太难受了

wodetu.cn
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-13 12:32:02 | 显示全部楼层
#include<stdio.h>
int main()
{
        int n = 1;
        scanf("%d",&n);
        switch(n)
        {
                case 1:
                        printf("n==1");
                        break;
                case 3:
                        printf("n==3");
                        brealk;
                case 100:
                        printf("n=100");
                        break;
        }
}
push        ebp
mov        ebp, esp
sub        esp, 8
mov        dword ptr [ebp-8], 1
lea        eax, [ebp-8]
push        eax
push        offset unk_417160
call        sub_401130
add        esp, 8
mov        ecx, [ebp-8]
mov        [ebp-4], ecx
cmp        dword ptr [ebp-4], 1
jz        short loc_401038
cmp        dword ptr [ebp-4], 3
jz        short loc_401047
jmp        short loc_401063
{
push         offset aN1
call         sub_4010F0
add        esp, 4
}
jmp         short loc_401063
{
push         offset aN1
call         sub_4010F0
add        esp, 4
}
jmp         short loc_401063
{
push         offset aN1
call         sub_4010F0
add        esp, 4
}
xor        eax, eax
mov        esp, ebp
pop        ebp
retn
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-13 12:34:39 | 显示全部楼层    本楼为最佳答案   
这段代码是一个简单的 C 语言程序,用于根据用户输入的值 n 执行不同的逻辑。以下是代码的详细解释:

首先,在 main 函数中,一个整型变量 n 被初始化为 1,并使用 scanf 函数从用户输入中读取 n 的新值。

然后,程序进入一个 switch 语句,根据 n 的值执行不同的逻辑。对于每个 case 分支,都有相应的打印语句和 break 语句用于跳出 switch 语句。

现在来分析汇编代码片段:
push ebp                     ; 保存旧的基址指针到栈中
mov ebp, esp                 ; 设置新的基址指针为当前栈顶
sub esp, 8                   ; 在堆栈上分配 8 字节的空间(用于局部变量和临时数据)

mov dword ptr [ebp-8], 1     ; 将值 1 存储到 ebp-8(局部变量 n)中
lea eax, [ebp-8]             ; 计算局部变量 n 的地址,并将其存储到 eax 寄存器中
push eax                     ; 将局部变量 n 的地址推入栈中(作为函数调用的参数)
push offset unk_417160       ; 推入一个位置未知的常量值作为第二个参数
call sub_401130              ; 调用 sub_401130 函数

add esp, 8                   ; 执行函数调用后,根据调用规约恢复栈指针
mov ecx, [ebp-8]             ; 将局部变量 n 的值加载到 ecx 寄存器中
mov [ebp-4], ecx             ; 将 ecx 寄存器中的值存储回 [ebp-4](用于后续的比较操作)

cmp dword ptr [ebp-4], 1     ; 将 [ebp-4](n 的值)与 1 进行比较
jz short loc_401038          ; 如果相等,则跳转到 loc_401038 代码块
cmp dword ptr [ebp-4], 3     ; 将 [ebp-4](n 的值)与 3 进行比较
jz short loc_401047          ; 如果相等,则跳转到 loc_401047 代码块
jmp short loc_401063         ; 否则,跳转到 loc_401063 代码块

loc_401038:                  ; 标签 loc_401038
push offset aN1              ; 推入字符串 "n==1" 的地址作为参数
call sub_4010F0              ; 调用 sub_4010F0 函数(可能是用于打印字符串)
add esp, 4                   ; 根据调用规约恢复栈指针
jmp short loc_401063         ; 跳转到 loc_401063 代码块

loc_401047:                  ; 标签 loc_401047
push offset aN3              ; 推入字符串 "n==3" 的地址作为参数
call sub_4010F0              ; 调用 sub_4010F0 函数(可能是用于打印字符串)
add esp, 4                   ; 根据调用规约恢复栈指针
jmp short loc_401063         ; 跳转到 loc_401063 代码块

loc_401063:                  ; 标签 loc_401063
xor eax, eax                 ; 将 eax 寄存器清零
mov esp, ebp                 ; 恢复栈指针
pop ebp                      ; 恢复旧的基址指针
retn                         ; 返回

总之,这个程序的功能是根据用户输入的 n 的值执行相应的逻辑,并打印相应的信息。注意,汇编代码中的函数调用和其他细节可能使用了未给出的代码或数据。

关于你提出的两个问题:

Q:sub esp,8                    ->   源程序中只有一个参数,为啥此处不esp-4,而是esp-8 ?????
A:在这段代码中,sub esp, 8 操作是为了在堆栈上分配足够的空间来存储局部变量和临时数据。在大多数情况下,函数调用使用堆栈来传递参数和保存返回地址,所以在函数开始时先给堆栈分配一些额外的空间。
Q:mov ecx,[ebp-8]                ->   为啥不直接用【ebp-8】地址,而用ecx转到[ebp-4],再cmp。
A:关于第二个问题,这段代码是将 [ebp-8] 中的值加载到 ecx 寄存器中,并将其存储到 [ebp-4],而不直接使用 [ebp-8] 的原因可能是为了后续比较操作的方便。通过将值从 [ebp-8] 复制到 [ebp-4],可以方便地与其他值进行比较,而不需要再次访问 [ebp-8]。这样的操作可能是为了简化代码或者遵循特定的编码风格。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-13 13:16:35 | 显示全部楼层

大哥,什么意思 没懂
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-13 13:18:49 | 显示全部楼层
HWitty 发表于 2023-7-13 13:16
大哥,什么意思 没懂

图床
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-22 12:12

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表