【问题标题】:Comparing Inputted Word to Array in x86 GNU GAS Assembly在 x86 GNU GAS 程序集中将输入的字与数组进行比较
【发布时间】:2020-10-16 21:33:40
【问题描述】:

这实际上是我今天关于这个特殊问题的第二个问题,但另一个问题很快就得到了回答。

本质上,我试图接收一串字母(没有数字或符号),然后将每个输入的字母与代表北约军事音标(Alpha、Bravo、Charlie、等)并输出与该字母等效的军事代表。

这就是我卡住的地方。我对组装相当陌生,这是一项家庭作业,因此非常需要和感谢帮助。我的教授不擅长提供资源来学习这些东西,而且很难在网上找到解决确切问题的好资源。

任何帮助将不胜感激。具体如何比较每个字母输入到数组。我已经成功地将输入存储在一个变量中。

下面是我正在尝试做的 C# 表示。

class MilAlpha
{
    static void Main(string[] args)
    {
        string input;
        string[] miliAlpha = { "Alpha", "Beta", "Charlie", "Delta", "Echo", "Foxtrot", "Golf", 
                               "Hotel", "India", "Juliet", "Kilo", "Lima", "Mike", "November",
                               "Oscar", "Papa", "Quebec", "Romeo", "Sierra", "Tango", "Uniform",
                               "Victor", "Whiskey", "X-Ray", "Yankee", "Zulu" };

        Console.WriteLine("Enter a string of text: ");
        input = Console.ReadLine();

        for (int i = 0; i < input.Length; i++) {
            for (int j = 0; j < miliAlpha.Length; j++) {

                if (input[i] == ' ')
                    Console.WriteLine("\n")
                
                string temp = miliAlpha[j].ToLower();

                if (input[i] == temp[0])
                    Console.WriteLine("\n" + miliAlpha[j] + "\n");

            }
        }

        Console.ReadKey();
    }
}

编辑:

所以我相信这应该做我想做的事,但它似乎没有按预期工作。它在调试器中比较正确的东西,但是当它打印数组的相应部分时,它根本不打印任何东西。

.section .data

MAlpha:
.asciz  "Alpha    \n"
.equ    ElementLen, .-MAlpha
.asciz  "Bravo    \n"
.asciz  "Charlie  \n"
.asciz  "Delta    \n"
.asciz  "Echo     \n"
.asciz  "Foxtrot  \n"
.asciz  "Golf     \n"
.asciz  "Hotel    \n"
.asciz  "India    \n"
.asciz  "Juliet   \n"
.asciz  "Kilo     \n"
.asciz  "Lima     \n"
.asciz  "Mike     \n"
.asciz  "November \n"
.asciz  "Oscar    \n"
.asciz  "Papa     \n"
.asciz  "Quebec   \n"
.asciz  "Romeo    \n"
.asciz  "Sierra   \n"
.asciz  "Tango    \n"
.asciz  "Uniform  \n"
.asciz  "Victor   \n"
.asciz  "Whiskey  \n"
.asciz  "X-Ray    \n"
.asciz  "Yankee   \n"
.asciz  "Zulu     \n"
.asciz  "         \n"
.equ    MAlphaLen, .-MAlpha

Input:
.fill   80
.equ    InputLen, .-Input

InputMSG:
.ascii  "Please enter a word: "
.equ    InputMSGLen, .-InputMSG

BlankLine:
.ascii  "\n"
.equ    BlankLineLen, .-BlankLine

Converting:
.ascii  "\nConverting to NATO Alphabet...\n\n"
.equ    ConvertingLen, .-Converting

.section .bss
.section .text
.globl   _start

GetInput:
    movl    $4, %eax
    movl    $1, %ebx
    movl    $InputMSG, %ecx
    movl    $InputMSGLen, %edx
    int     $0x80

    movl    $3, %eax
    movl    $0, %ebx
    movl    $Input, %ecx
    movl    $InputLen, %edx
    int     $0x80
    ret

PrintInput:
    movl    $4, %eax
    movl    $1, %ebx
    movl    $BlankLine, %ecx
    movl    $BlankLineLen, %edx
    int     $0x80

    movl    $4, %eax
    movl    $1, %ebx
    movl    $Input, %ecx
    movl    $InputLen, %edx
    int     $0x80

    movl    $4, %eax
    movl    $1, %ebx
    movl    $Converting, %ecx
    movl    $ConvertingLen, %edx
    int     $0x80
    ret

Convert:
    # Get first letter of input string
    # Compare letter to first letter of each array entry
    # When match is found, print Array entry to screen
    # Repeat until end of input string

    movl    $Input, %eax
    movl    $MAlpha, %edi
    call    Loop
    ret

Loop:
    movb    (%eax), %al
    cmp     $0x0A, %al
    je      Finished

    call    CompareAlpha

    jmp     Loop

CompareAlpha:
    movb    (%edi), %bl
    cmpb    %bl, %al
    je      PrintWord
    addl    $ElementLen, %edi
    jmp     CompareAlpha

PrintWord:
    movl    $4, %eax
    movl    $1, %ebx
    movl    (%edi), %eax
    movl    $ElementLen, %edx
    int     $0x80

Finished:
    call    ExitProg

_start:
    call    GetInput
    call    PrintInput
    call    Convert
    call    ExitProg

PrintMAlpha:
    movl    $4, %eax
    movl    $1, %ebx
    movl    $MAlpha, %ecx
    movl    $MAlphaLen, %edx
    int     $0x80

ExitProg:
    movl    $1, %eax
    movl    $0, %ebx
    int     $0x80

【问题讨论】:

  • 我认为“比较”的想法会误导你。明智的做法是使用查找表,使用字母索引到字符串数组(使用适当的边界检查);您永远不会将字母与字符串进行比较。尝试先用 C 等高级语言编写它,然后您可能会更好地了解该做什么。
  • 但总的来说,Stack Overflow 期望问题比这更集中。这个网站并不是真正为“我如何开始”问题或家庭作业帮助而设置的。这往往需要与某人进行长时间的反复交流来帮助您,而 Stack Overflow 是围绕可以提出、回答和完成的问题而构建的。
  • @NateEldredge 那么还有一个更具体的问题,如何将数组用作查找表?我是一个相当有经验的高级程序员,但是汇编对我来说是全新的,即使按照你的建议做了我也遇到了麻烦(我是在别人的建议下做的,很有趣)。
  • 那么把你的 C 代码放在问题中怎么样?或许还有你迄今为止编写的任何骨架汇编代码?
  • 最好知道您是在编写 32 位还是 64 位代码,以及您将使用什么操作系统来组装和运行您的代码(这决定了要使用的适当代码模型) .

标签: linux assembly linux-kernel gnu 32-bit


【解决方案1】:

这里有一些错误可以帮助您入门:

  1. Loop 中,您将指向输入字符串的指针保留在%eax 中,但是您将字符加载到%al 中,这是%eax 的低字节,从而破坏了它的值。为其中一个选择另一个寄存器。

  2. 您永远不会在Loop 中增加您的指针,因此它将永远循环(如果它没有由于您的其他错误之一而首先崩溃)。

  3. CompareAlpha 不会在连续调用时重置 %edi。因此,如果第一个字符是'H',则在调用后%edi 将指向"Hotel"。如果下一个字符是ECompareAlpha 将从"Hotel" 开始向前搜索。当然它不会找到它,所以它会跑出数组的末尾并崩溃。

  4. PrintWord 将字符串的四个字节加载到%eax(覆盖系统调用号),而它应该将字符串的地址加载到%ecx。将movl (%edi), %eax 替换为movl %edi, %ecx(注意它现在是寄存器到寄存器的移动,而不是从内存中加载)。

  5. PrintWordclobbers 注册%eax, %ebx, %ecx, %edx,其中一些调用者期望保持不变。要么推送和弹出这些寄存器,要么在调用之前重写CompareAlpha

  6. PrintWord 最后缺少一个ret,所以它落入ExitProg

修复这些后,我能够成功转换字符串"HELLO"

这些都可以通过在gdb 调试器(si 命令)中单步执行代码并观察寄存器的内容(display $eax)以及它们指向的内容(display/s $edi 等)来找到。我建议练习一下。

请注意,一种更有效的设计,而不是通过代码字数组进行线性搜索,而是简单地对其进行索引。把你的字符减去'A' (0x41) 的ASCII 码,乘以$ElementLen,然后加上$MAlpha。现在您有了一个指向所需代码字的指针,而无需循环。如果使用your other post 中的辅助指针数组,则更容易,因为每个指针的长度为4,因此您可以使用SIB 寻址模式并执行movl MAlpha(,%eax,4), %edi;确保%eax 的高 24 位清零。这也避免了用空格填充所有代码字的需要(尽管你需要编写自己的 strlen 来计算长度,或者有一个单独的长度数组,或者一次写出一个字节,直到你看到最后的0)。

此外,作为一般提示,最好记录下您的每个子例程:它究竟做了什么,它期望在哪些寄存器中输入并离开它的输出,以及它破坏了哪些寄存器?您可能想尝试在它们之间建立一些共性,甚至可以创建自己的标准调用约定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-30
    • 1970-01-01
    相关资源
    最近更新 更多