【问题标题】:NASM - segmentation fault and other problemsNASM - 分段错误和其他问题
【发布时间】:2012-02-16 02:47:13
【问题描述】:

这是我第一次在这里发帖。我不确定我的格式是否正确,如果我搞砸了,请原谅我。

无论如何,这应该接受两个输入,一个减半,另一个加倍,然后打印它们。它不应该正常工作,因为输入数据是字符,但输出仍然令人困惑:

[poise] [/home/a/a_mccr/terminal] > ./assignment2
Please enter a four-digit number, negative or positive
1234
The number you entered is
Half the entered value is
ÞH
Double the entered value is
x#      ÞH
Segmentation fault

它不会打印出我的输入(即 1234),然后每次输出都是 PH,然后是 X# PH。所有这些都向我表明输入没有被存储,但我不知道为什么。此外,我在程序结束时遇到了一个神秘的分段错误......帮助!代码如下:

segment .data                   ;to compile use:        nasm -f elf assignment2.asm
                            ;                       ld -o assignment2 assignment2.o

    msg1 db 'Please enter a four-digit number, negative or positive', 0xA
    len1 equ $-msg1         ;length of 1st message
    msg2 db 'The number you entered is', 0xA
    len2 equ $-msg2         ;length of 2nd message
    msg3 db 'Half the entered value is', 0xA
    len3 equ $-msg3         ;length of 3rd message
    msg4 db 'Double the entered value is', 0xA
    len4 equ $-msg4         ;length of 4th message

segment .bss

    input2 resb 3           ;reserve 5 bytes for the entered number
    input resb 3            ;reserve 5 bytes for the entered number

segment .text
    global _start

_start:
    mov eax, 4      ;select kernel call 4, the write function
    mov ebx, 1      ;use the default output device (print in terminal)
    mov ecx, msg1   ;set the pointer to msg
    mov edx, len1   ;set the length to len
    int 0x80        ;call write function

    mov eax, 3      ;select the kernel read function
    mov ebx, 0      ;use the default input device (user txt input)
    mov ecx, input  ;pointer to input variable
    int 0x80        ;invoke kernel read function

    mov eax, 4      ;select kernel call 4, the write function
    mov ebx, 1      ;use the default output device (print in terminal)
    mov ecx, msg2   ;set the pointer to msg2
    mov edx, len2   ;set the length to len2
    int 0x80        ;call write function

    mov eax, 4      ;select kernel call 4, the write function
    mov ebx, 1      ;use the default output device (print in terminal)
    mov ecx, input  ;set the pointer to input
    int 0x80        ;call write function

    mov eax, [input]        ;move input to eax register
    mov ebx, [input]        ;move input to ebx register

    shr eax, 1      ;shift eax 1 place to the right
    shl ebx, 1      ;shift ebx 1 place to the left

    mov [input], eax        ;move contents of eax to input
    mov [input2], ebx       ;move contents of ebx to input2

    mov eax, 4      ;Write message about half
    mov ebx, 1      ;use the default output device (print in terminal)
    mov ecx, msg3   ;set the pointer to msg3
    mov edx, len3   ;set the length to len3
    int 0x80        ;call write function

    mov eax, 4      ;write contents of input
    mov ebx, 1      ;use the default output device (print in terminal)
    mov ecx, input  ;set the pointer to input
    int 0x80        ;call write function

    mov eax, 4      ;write message about double
    mov ebx, 1      ;use the default output device (print in terminal)
    mov ecx, msg4   ;set the pointer to msg4
    mov edx, len4   ;set the length to len4
    int 0x80        ;call write function

    mov eax, 4      ;write contents of input2
    mov ebx, 1      ;use the default output device (print in terminal)
    mov ecx, input2 ;set the pointer to input2
    int 0x80        ;call write function

_exit:
    mov eax, 1      ;standard exit
    mov ebx, 0      ;0 is normal
    int 0x80

【问题讨论】:

    标签: assembly segmentation-fault nasm


    【解决方案1】:

    在读取输入时,您似乎忘记指定要读取的长度:

    mov eax, 3      ;select the kernel read function
    mov ebx, 0      ;use the default input device (user txt input)
    mov ecx, input  ;pointer to input variable
    int 0x80        ;invoke kernel read function
    

    假设edx 的旧值将是read(2) 的长度——这将比您的input 空间长得多。 (还有 5 个字节?当然看起来很奇怪。此外,注释似乎与代码不匹配,但这可能是我的无知而不是您的代码。)

    【讨论】:

    • 有些 cmets 并不完全正确,因为我有时会在编辑一行后忘记更新它们。我实际上使用了 3 个字节,因为我最多需要五个 4 位点(负号和四个整数)。我应该放什么来设置长度?
    • 哦,还有,如果它是一个实例变量,我想我不必告诉它长度(TA 没有在他展示给我们的示例代码中)
    • 啊哈,三个字节绝对不足以容纳四个字节1234——而且,我已经很久没有这样做了,但可能是空间在您点击^D 结束输入之前,\n 是必需的。到目前为止它仍然是纯文本。
    【解决方案2】:

    让我说对了:

    1. 您读取一个字符串作为输入
    2. 你把它放在一个寄存器中(实际上一个 32 位寄存器的宽度刚好可以容纳一个 4 字符的字符串)
    3. 您将字符串重新解释为整数(这里您实际上需要将其从十进制转换为二进制)
    4. 你减半/加倍
    5. 您将毫无意义的减半字符流发送到输出
    6. 您在屏幕上收到垃圾。

    您需要在输入和输出之前将收到的 ASCII 字符串从十进制转换为二进制并返回。如果你不使用atoi() 或类似的,你可以编写自己的版本,这实际上并不难。

    您需要为字符串保留更多字节,一个 32 位的数字可能长达 10 个字符。你会这样做吗,你自己可能已经看到了那里的错误,因为你可能发现很难将 10 字节的字符串压缩到 32 位寄存器中。

    【讨论】:

    • 我知道该程序无法按预期方式运行。我的教授认为他在给我们上一堂数据类型的课,让我们编写一个不起作用的程序。我认为他的教学方法可能需要一些工作,但无论哪种方式,我真正的问题是:
    • 1.我得到一个分段错误。我不知道这到底是什么意思。你是说发生这种情况是因为 32 位寄存器不够大,无法存储我要操作的数据吗? 2. 它根本不会打印存储在输入变量中的数据(我指的是这里的第二个 write 函数调用)。对于我的一生,我无法弄清楚为什么会发生这种情况。
    • 和3、shift之后好像总是打印一样的东西,理论上每次应该都是不同的一组乱码吧?
    • 如何将 ASCII 转换为十进制或二进制?你能解释一下吗?
    • @Imray 使用atoi() 或类似功能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-29
    • 2016-09-10
    • 2014-01-31
    • 2023-03-12
    • 1970-01-01
    • 2020-08-10
    • 2013-07-24
    相关资源
    最近更新 更多