NASM内存寻址

时间:2016-12-07 19:17:28

标签: assembly nasm memory-address

我正在玩程序命令行参数。特别是我试图对字符串argv [1]进行一些测试。如果我使用两步法获取地址到argv [1],我的代码运行正常。

mov ebx, [ebp+12]
mov eax, [ebx+4] ; address of argv[1]

如果我使用一步,我的程序会打印乱码。

mov eax, [ebp+16] ; address of argv[1]

假设任何一种方法现在都引用地址[ebp + 16],我是否错误?我错过了一些微不足道的事情吗?

2 个答案:

答案 0 :(得分:4)

在处理程序集中指针的指针时很容易混淆。

argv是一个“字符串数组”或更好的指向char的指针数组,因为在C数组中作为参数传递时会衰减成指向其项类型的指针,事实上argv它是一个指向char或char** argv指针的指针。

这告诉我们,我们需要两个解除引用来访问任何字符串的字符,一个访问任何指向任何字符串的指针。

假设 cdecl 约定,其中参数以相反的顺序在堆栈上传递,并假设设置标准帧指针的标准序言,我们得到argc的值为ebp+0ch
请注意ebp具有指针的语义,因此ebp+0ch只是指针算术以获取另一个指针,这次是argc值。

如果我们愿意给ebp+0ch一个C类型,它将是char***,因此需要两个解除引用来访问指针argv[1]

argv[1]转换为ESI的代码是:

;typeof(ebp+0ch) = char***

mov esi, DWORD [ebp+0ch]      ;1st defer, esi = argv, typeof(esi) = char**
mov esi, DWORD [esi+04h]      ;2nd defer, esi = argv[1], typeof(esi) = char*

;Optional, Get a char
mov al, BYTE [esi]            ;3rd defer, al = argv[1][0], typeof(al) = char

类型检查。

听起来令人困惑? 让我们画出那些指针!

       The stack                                     The memory

100ch | 2000h  | argv                         2000h | 2008h   | argv[0]
1008h | 2      | argc                         2004h | 2010h   | argv[1]
1004h | yyyyyy | return address               2008h | file    | argv[0][0..3]
1000h | xxxxxx | old frame pointer            200ch | .a\0\0  | argv[0][4..7]
                                              2010h | -arg    | argv[1][0..3]
EBP = 1000h                                   2014h | 1\0\0\0 | argv[1][4..7]

ebp+0ch为1000h + 0ch = 100ch,它是argv值的地址。
mov esi, DWORD [ebp+0ch]mov esi, DWORD [100ch]类似,它将ESI设置为2000h 2000h是argv的值,它是一个数组,因此它是argv[0]的地址。

argv[1]的地址是前面四个字节,因此2000h + 04h = 2004h mov esi, DWORD [esi+04h]mov esi, DWORD [2004h]类似,它将ESI设置为2010h 2010h是字符串“-arg1”的地址。

请注意,上图不符合C和C ++标准,因为argv[argc]必须为0 我把它留在了画面之外。

答案 1 :(得分:-2)

这是你问题的答案。

mov eax, [ebp+16] 
lea ebx, [ebp+12] 
mov eax, [ebx+4]

mov eax, [ebp+16]
mov ebx, ebp
add ebx, 12
mov eax, [ebx+4]

前者保存了几个字节的代码,但它们在功能上是等效的。