0

This is actually my second question about this particular problem today, but the other one was answered pretty quickly.

In essence, I am trying to take in a string of letters (no numbers or symbols) and then compare each inputted letter to an array of .asciz values that represent the NATO Military Phonetic Alphabet (Alpha, Bravo, Charlie, etc.) and output the representative Military equivalent to the letter.

This is where I am stuck. I'm fairly new to Assembly and this is a homework assignment, so help is much needed and appreciated. My professor is not great at offering resources to learn this stuff and it's difficult to find good resources for exact problems online.

Any help would be much appreciated. Specifically on how to compare each letter input to the array. I've already successfully stored the input in a variable.

Below is a C# representation of what I am attempting to do.

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();
    }
}

EDIT:

So I believe this should do what I am trying to do, but it doesn't seem to work as intended. It compares the correct things in the debugger, but when it goes to print the respective portion of the array, it simply doesn't print anything.

.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
Aphemra
  • 103
  • 7
  • I think the idea of "comparing" is misleading you. The sensible way to do this would be as a lookup table, using the letter to index into the array of strings (with appropriate bounds checking); you never compare the letter against the strings. Try writing it in a somewhat higher-level language such as C first, and then you may have a better idea of what to do. – Nate Eldredge Oct 16 '20 at 21:51
  • 1
    But in general, Stack Overflow expects questions to be more focused than this. This site is not really set up for "how can I get started" questions or homework help. That tends to call for an extended back-and-forth with someone to help you, and Stack Overflow is built around questions that can be asked and answered and done. – Nate Eldredge Oct 16 '20 at 21:52
  • @NateEldredge Well then a more specific question, how does one go about using the array as a lookup table? I am a fairly experience high level programmer, but assembly is brand new to me and I'm having trouble even after doing as you suggested (which I did at the suggestion of someone else, funnily enough). – Aphemra Oct 16 '20 at 21:54
  • How about putting your C code in the question, then? And perhaps any skeletal assembly code you have written thus far? – Nate Eldredge Oct 16 '20 at 21:54
  • It would also be good to know if you are writing 32- or 64-bit code, and what OS you will be using to assemble and run your code (this determines the appropriate code model to use). – Nate Eldredge Oct 16 '20 at 21:58
  • @NateEldredge The title of the question cites 32-bit and GNU which is Linux. My code is on my laptop, I'm retrieving it and will add it momentarily. – Aphemra Oct 16 '20 at 22:10
  • Okay. It was not quite unambiguous; x86 can also refer to x86-64, and the GNU assembler can be used on many platforms other than Linux. – Nate Eldredge Oct 16 '20 at 22:10
  • @NateEldredge -- Added my code. It's C# tho. – Aphemra Oct 16 '20 at 22:16
  • I see - you really are searching through the array. What I meant by a lookup table was something like `milliAlpha[c - 'A']`. – Nate Eldredge Oct 16 '20 at 22:27
  • @NateEldredge Yeah, which is kind of where my disconnect is coming from, I think. I understand how it works, I just don't really know where to begin in terms of assembly. – Aphemra Oct 16 '20 at 22:31

1 Answers1

1

Here's a few bugs to get you started:

  1. In Loop, you are keeping the pointer to the input string in %eax, but you load the character into %al which is the low byte of %eax, thus trashing its value. Pick another register for one of them.

  2. You never increment your pointer in Loop, so it will loop forever (if it doesn't crash first due to one of your other bugs).

  3. CompareAlpha doesn't reset %edi on successive calls. So if the first character is 'H', %edi will be left pointing to "Hotel" after the call. If the next character is E, CompareAlpha will search forward for it starting from "Hotel". Of course it won't find it, so it runs off the end of the array and crashes.

  4. PrintWord loads four bytes of the string into %eax (overwriting the system call number), whereas it should be loading the address of the string into %ecx. Replace movl (%edi), %eax by movl %edi, %ecx (note it is now a register-to-register move and not a load from memory).

  5. PrintWord clobbers registers %eax, %ebx, %ecx, %edx, some of which its caller is expecting to remain unchanged. Either push and pop those registers, or rewrite CompareAlpha to do so before calling it.

  6. PrintWord is missing a ret at the end, so it falls through into ExitProg.

After fixing these, I was able to successfully convert the string "HELLO".

These were all findable by single-stepping the code in the gdb debugger (si command) and watching the contents of registers (display $eax) and what they point to (display/s $edi, etc). I suggest practicing this.

Note that a more efficient design, instead of linear search through the array of codewords, would be to simply index into it. Take your character and subtract the ASCII code of 'A' (0x41), multiply by $ElementLen, and add to $MAlpha. Now you have a pointer to the desired codeword without looping. If you use an auxiliary array of pointers as in your other post, this is even easier as each pointer has length 4, so you can use the SIB addressing mode and do movl MAlpha(,%eax,4), %edi; make sure the high 24 bits of %eax are zeroed. This also avoids the need for padding all the code words with spaces (though then you'll need to write your own strlen to compute the length, or have a separate array of lengths, or write out one byte at a time until you see the 0 at the end).

Also, as a general tip, it would be wise to document each of your subroutines: what exactly does it do, in which registers does it expect its inputs and leave its outputs, and which registers does it clobber? You may want to try to have some commonality between these, perhaps even creating your own standard calling conventions.

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82