将输入的字与 x86 GNU GAS 程序集中的数组进行比较
Comparing Inputted Word to Array in x86 GNU GAS Assembly
这实际上是我今天关于这个特定问题的第二个问题,但另一个问题很快就得到了回答。
本质上,我试图输入一串字母(没有数字或符号),然后将每个输入的字母与代表北约军事音标的 .asciz
值数组进行比较(Alpha, Bravo, Charlie, etc.) 并输出对应于该字母的代表军事等价物。
这就是我卡住的地方。我是 Assembly 的新手,这是一项家庭作业,因此非常需要和感谢帮助。我的教授不擅长提供学习这些东西的资源,而且很难在网上找到解决确切问题的好资源。
如有任何帮助,我们将不胜感激。具体是关于如何比较输入到数组中的每个字母。我已经成功地将输入存储在一个变量中。
下面是我正在尝试执行的操作的 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 , %eax
movl , %ebx
movl $InputMSG, %ecx
movl $InputMSGLen, %edx
int [=11=]x80
movl , %eax
movl [=11=], %ebx
movl $Input, %ecx
movl $InputLen, %edx
int [=11=]x80
ret
PrintInput:
movl , %eax
movl , %ebx
movl $BlankLine, %ecx
movl $BlankLineLen, %edx
int [=11=]x80
movl , %eax
movl , %ebx
movl $Input, %ecx
movl $InputLen, %edx
int [=11=]x80
movl , %eax
movl , %ebx
movl $Converting, %ecx
movl $ConvertingLen, %edx
int [=11=]x80
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 [=11=]x0A, %al
je Finished
call CompareAlpha
jmp Loop
CompareAlpha:
movb (%edi), %bl
cmpb %bl, %al
je PrintWord
addl $ElementLen, %edi
jmp CompareAlpha
PrintWord:
movl , %eax
movl , %ebx
movl (%edi), %eax
movl $ElementLen, %edx
int [=11=]x80
Finished:
call ExitProg
_start:
call GetInput
call PrintInput
call Convert
call ExitProg
PrintMAlpha:
movl , %eax
movl , %ebx
movl $MAlpha, %ecx
movl $MAlphaLen, %edx
int [=11=]x80
ExitProg:
movl , %eax
movl [=11=], %ebx
int [=11=]x80
这里有一些错误可以帮助您入门:
在Loop
中,您将指向输入字符串的指针保留在%eax
中,但是您将字符加载到%al
中,这是%al
中的低字节%eax
,从而破坏了它的价值。为其中之一选择另一个寄存器。
您永远不会在 Loop
中递增您的指针,因此它将永远循环(如果它没有因您的其他错误之一而首先崩溃)。
CompareAlpha
不会在连续调用时重置 %edi
。因此,如果第一个字符是 'H'
,%edi
将在调用后指向 "Hotel"
。如果下一个字符是 E
,CompareAlpha
将从 "Hotel"
开始向前搜索它。它当然不会找到它,所以它会跑到数组的末尾并崩溃。
PrintWord
将字符串的四个字节加载到 %eax
(覆盖系统调用号),而它应该将字符串的地址加载到 %ecx
.将 movl (%edi), %eax
替换为 movl %edi, %ecx
(注意它现在是 register-to-register 移动而不是从内存加载)。
PrintWord
破坏了寄存器 %eax, %ebx, %ecx, %edx
,其中一些它的调用者期望保持不变。压入和弹出这些寄存器,或者重写 CompareAlpha
在调用它之前这样做。
PrintWord
末尾缺少一个 ret
,因此它落入 ExitProg
.
修复这些后,我能够成功转换字符串 "HELLO"
。
这些都可以通过 single-stepping 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)。
此外,作为一般提示,明智的做法是记录您的每个子例程:它究竟做了什么,它期望在哪些寄存器中输入并保留其输出,以及它破坏了哪些寄存器?您可能想尝试在它们之间建立一些共性,甚至可能创建您自己的标准调用约定。
这实际上是我今天关于这个特定问题的第二个问题,但另一个问题很快就得到了回答。
本质上,我试图输入一串字母(没有数字或符号),然后将每个输入的字母与代表北约军事音标的 .asciz
值数组进行比较(Alpha, Bravo, Charlie, etc.) 并输出对应于该字母的代表军事等价物。
这就是我卡住的地方。我是 Assembly 的新手,这是一项家庭作业,因此非常需要和感谢帮助。我的教授不擅长提供学习这些东西的资源,而且很难在网上找到解决确切问题的好资源。
如有任何帮助,我们将不胜感激。具体是关于如何比较输入到数组中的每个字母。我已经成功地将输入存储在一个变量中。
下面是我正在尝试执行的操作的 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 , %eax
movl , %ebx
movl $InputMSG, %ecx
movl $InputMSGLen, %edx
int [=11=]x80
movl , %eax
movl [=11=], %ebx
movl $Input, %ecx
movl $InputLen, %edx
int [=11=]x80
ret
PrintInput:
movl , %eax
movl , %ebx
movl $BlankLine, %ecx
movl $BlankLineLen, %edx
int [=11=]x80
movl , %eax
movl , %ebx
movl $Input, %ecx
movl $InputLen, %edx
int [=11=]x80
movl , %eax
movl , %ebx
movl $Converting, %ecx
movl $ConvertingLen, %edx
int [=11=]x80
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 [=11=]x0A, %al
je Finished
call CompareAlpha
jmp Loop
CompareAlpha:
movb (%edi), %bl
cmpb %bl, %al
je PrintWord
addl $ElementLen, %edi
jmp CompareAlpha
PrintWord:
movl , %eax
movl , %ebx
movl (%edi), %eax
movl $ElementLen, %edx
int [=11=]x80
Finished:
call ExitProg
_start:
call GetInput
call PrintInput
call Convert
call ExitProg
PrintMAlpha:
movl , %eax
movl , %ebx
movl $MAlpha, %ecx
movl $MAlphaLen, %edx
int [=11=]x80
ExitProg:
movl , %eax
movl [=11=], %ebx
int [=11=]x80
这里有一些错误可以帮助您入门:
在
Loop
中,您将指向输入字符串的指针保留在%eax
中,但是您将字符加载到%al
中,这是%al
中的低字节%eax
,从而破坏了它的价值。为其中之一选择另一个寄存器。您永远不会在
Loop
中递增您的指针,因此它将永远循环(如果它没有因您的其他错误之一而首先崩溃)。CompareAlpha
不会在连续调用时重置%edi
。因此,如果第一个字符是'H'
,%edi
将在调用后指向"Hotel"
。如果下一个字符是E
,CompareAlpha
将从"Hotel"
开始向前搜索它。它当然不会找到它,所以它会跑到数组的末尾并崩溃。PrintWord
将字符串的四个字节加载到%eax
(覆盖系统调用号),而它应该将字符串的地址加载到%ecx
.将movl (%edi), %eax
替换为movl %edi, %ecx
(注意它现在是 register-to-register 移动而不是从内存加载)。PrintWord
破坏了寄存器%eax, %ebx, %ecx, %edx
,其中一些它的调用者期望保持不变。压入和弹出这些寄存器,或者重写CompareAlpha
在调用它之前这样做。PrintWord
末尾缺少一个ret
,因此它落入ExitProg
.
修复这些后,我能够成功转换字符串 "HELLO"
。
这些都可以通过 single-stepping 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)。
此外,作为一般提示,明智的做法是记录您的每个子例程:它究竟做了什么,它期望在哪些寄存器中输入并保留其输出,以及它破坏了哪些寄存器?您可能想尝试在它们之间建立一些共性,甚至可能创建您自己的标准调用约定。