【问题标题】:How do I maintain stack in NASM using in Ubuntu11.04如何在 Ubuntu11.04 中使用 NASM 维护堆栈
【发布时间】:2013-03-05 17:34:29
【问题描述】:

对于我的项目工作,我测试了一个代码 sn-p。我发现这段代码sn-p由于使用堆栈而出现分段错误。但是,我必须使用堆栈来解决它。谁能帮我找到出了问题?我的程序将显示字符串变量的第二个字符。我的代码 sn-p 如下:

section.data
  string db "test",10,0
  msg2   db "%c",10,0
main:

xor eax,eax
mov eax, string
mov ebx,1    ; suppose I want to get the second character of string. SO I store the index of that character in ebx

pusha
push eax
push ebx
add esp,8
popa

pop dword[ebx]   ;  **I assume that this following 3 lines arise segmentation fault**   
pop eax          ;
mov bl,[eax+ebx] ; I want to move the fisrt character to BL using the index value stored in ebx which i popped just.

pusha
push ebx
call putchar
add esp,4
popa

pusha
push msg2
call printf
add esp,4
popa

在这里,为了您的善意,我想明确说明这段代码 sn-p 的目的是了解如何操作堆栈。

在这里,@nrz 最近给了我以下代码的想法,我在这里编辑了上面的代码:

  section.data
    string db "test",10,0
    msg2   db "%c",10,0
  main:
    xor eax,eax
    mov eax, string
    mov ebx,1  ; suppose I want to get the second character of string. SO I store the index of that character in ebx
    mov   eax,string
    movzx eax,byte [eax]
    push  eax        ; these push and pop are for solving it using the stack,
    pop   ebx
    pusha
    push ebx
    call putchar
    add esp,4
    popa
    pusha
    push msg2
    call printf
    add esp,4
    popa

我的查询具体是:

  1. 我会给出索引值。它应该在ebx 寄存器中吗?

  2. 最重要的是,我使用堆栈的主要想法是使用我之前推入ebx 的索引值来访问string 变量的每个字符。 [这是强制性的。有可能吗?]

  3. 我也想将输出存储在一个 8 位寄存器中。

    所以我的全部想法是这样的:

    mov al, [string+ebx]   ;is it possible?
    

    我必须从堆栈中取出ebx 的值。我将在ebx 中输入一个值,然后在push ebx 中输入一个值,在mov al,[string+ebx] 时,我将在pop ebx 中获取mov 指令的值。说明更有可能是这样的:

     pop ebx  
     mov al,[string+dword[ebx]]  ;which is a wrong statement shown by NASM
    

我热切期待您的回复。

谢谢,

【问题讨论】:

  • push ebxcall putchar 之前推送的值是ASCII 码,不是任何类型的索引或内存地址。通常,使用该值不可能“访问字符串的每个字符”。大致有两种打印方式:1. 循环遍历字符串,并在当时打印它的字符(例如,使用call putchar,如您的代码中所示),或 2. 一次打印完整的字符串,使用 @ 987654337@ 或 Linux API write 函数 (4)。但是如果字符串长度被预先确定为 4 个字节,比如test,这是可能的。字符串长度总是4字节吗?
  • mov al, [string+ebx] 肯定是一个可能的指令,但 它不使用堆栈,如果这是要求的话。请参阅我编辑的“正常”mov al, [string+ebx] 代码和“使用堆栈”代码的答案:push dword [ebx+string]and dword [esp], 0x000000ffpop eax
  • @nrz:我不知道,我该如何向你表达我的感激之情,并表示我的遗憾,可能是我的英语知识不足并没有帮助你理解我的想法。我对此表示歉意。我提到我必须从堆栈中获取 ebx 的值。我将在 ebx 中输入一个值,然后 PUSH THE EBX 并在 mov al,[string+ebx] 时弹出 ebx 以获取 mov 指令的值。更有可能是 mov al,[string+dword[ebx]](这是 NASM 显示的错误语句)。但是在您的代码中,没有办法弹出 ebx 的值来执行“string”
  • 如果你不以任何方式处理堆栈,除了 pushpop 指令,push eaxpush ebxadd esp,8 是绝对没有必要的。它所做的只是先推送eax,然后推送ebx,然后将esp 恢复为原始值。所以和push eax,push ebx,pop ebx,pop eax是一样的;最后所有涉及的寄存器(eaxebxesp)都有它们的原始值。
  • 是的,那是因为您的堆栈不平衡:push eaxpush ebxadd esp,8pop ebxpop eax。每个push 减去esp 4,每个pop 加4 到esp,然后用add esp,8 再加8 到esp,导致堆栈不平衡。此外,整个push eaxpush ebxadd esp,8pop ebxpop eax 块是完全没有必要的。你应该把它关掉,因为它没有任何作用(除了作为一个非常基本的代码混淆)。如果您想使用pushpop 指令,无论如何都要保持堆栈平衡,否则很可能会出现分段错误。

标签: linux assembly x86 stack nasm


【解决方案1】:

代码中存在一些错误和不必要的说明:

移动 eax,字符串;这条线使 eax 指向字符串,但是...... xor eax,eax ;此行立即将 eax 归零。删除这一行。 移动 ebx,1 ;这条线是不必要的,但不会引起问题。 普萨;不必要。 推动 eax ;不必要。 推 ebx ;不必要。 添加 esp,8 ;不必要。 波帕;不必要。 pop dword[ebx] ; [1] = [esp], esp = esp+4, 可能导致分段错误。 流行音乐; eax = [esp],esp = esp+4 mov bl,[eax+ebx]

编辑:打印所有字符,只需遍历字符串:

部分数据 字符串数据库“测试”,10 string_length equ $-string ;字符串中的字符数。 ;字符串末尾不需要零。 msg2 数据库 "%c",10,0 主要的: xor eax,eax ; eax 是字符串的索引。 字符循环: push dword [eax+string] ;将 4 个第一个字符推入堆栈。 和 dword [esp], 0x000000ff ; x86 是 little-endian,所以第一个字符 ;是最低字节。 流行 ebx ;将字符的 ASCII 码弹出到 ebx 中。 普萨德 推 ebx 调用 putchar 添加 esp,4 波帕德 公司 cmp eax,string_length jb char_loop

编辑:新代码以匹配问题的变化,使用ebx作为索引。

部分数据 字符串数据库“测试”,10 string_length equ $-string ;字符串中的字符数。 ;字符串末尾不需要零。 msg2 数据库 "%c",10,0 主要的: xor eax,eax ;零 eax,用于 putchar。 异或 ebx,ebx ; ebx 是字符串的索引。 字符循环: ;push dword [ebx+string] ;将 4 个第一个字符推入堆栈。 ; 和 dword [esp], 0x000000ff ; x86 是 little-endian,所以第一个字符 ; ;是最低字节。 ;pop eax ;将字符的 ASCII 码弹出到 ebx 中。 mov al,[ebx+string] ;这是正常的做法。 ;以上3条指令“使用堆栈”, ;按照问题的要求。 普萨德 推入 调用 putchar 添加 esp,4 波帕德 公司 ebx cmp ebx,string_length jb char_loop

【讨论】:

  • 感谢您的友好回复。但我担心它会解决我的目的。我的目标是使用存储在 ebx 中的索引值从字符串变量中访问每个字符。在上面的问题部分,我使用您的代码重新编辑了我的问题,显示了我得到的输出。我的另一个问题是,您正在弹出 ebx,但您是什么时候推送的?
  • 它被推到正上方:push eax。我不确定我是否正确理解了您的问题。您能否编辑您的问题以明确您想用您的代码完成什么(有call putcharcall printf,引用不存在的msg2 等)以及您对可能的解决方案施加的限制是什么(“使用堆栈”不够具体)。
  • 您太客气了,我的导师。但是我的询问可能会对您造成干扰。不过还是希望你能回答。我要求我将使用存储在 ebx 中的 SUPPLIED 索引值访问“字符串”变量的每个字符,并且我想将值明确存储在 8 位寄存器中。我现在怀疑我的想法是否可行。
  • 请注意,在指令movzx eax,byte [eax]push eaxpop ebxebx(特别是bl)之后确实包含当前字符的ASCII 码 ,而不是字符串的索引。它只是一个 ASCII 码(嗯,它可以用作某处 font data 的索引,但它不是 string 的索引,不能用作这样)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-26
  • 2017-02-13
  • 1970-01-01
  • 1970-01-01
  • 2016-11-28
  • 1970-01-01
  • 2013-10-12
相关资源
最近更新 更多