compiler-inservice-s22 / Discussion

MIT License
0 stars 0 forks source link

How to use the *.S file? #31

Open PlusoneWang opened 2 years ago

PlusoneWang commented 2 years ago

Hi TAs,

I saved the sample RISC-V instructions in the README as test1.S, but I don't know how to use it.

image

image

BTW, I still have no idea that how to complete this assignment and intend to give up. If you have any suggestions, I would appreciate it.

LittleLaGi commented 2 years ago

同學你好:

... but I don't know how to use it.

你是指不知道如何編譯、執行自己的測試程式嗎? 你的第一張圖片下的指令是正確的 (第一行指令會將程式編譯成 elf 檔, 第二行指令會使用 RISC-V 的模擬器實際執行 elf 檔),執行時都會在一開始印出 bbl loader。 第二張圖片中會報錯是因為你少提供 io.c,所以 linker 找不到 printInt 函式的定義,照著第一張圖片的指令就可以了。 另外,就像前面的作業一樣,可以使用 make test 來測試所有的測資。

不知道從何下手的話可以參考一下 #29 這篇 issue, 有任何疑問的話都可以提出來~

補充 如果不知道該產生怎樣的組合語言,可以參考作業說明的Hint,利用下面的指令:

riscv32-unknown-elf-gcc -c -S [input C file] -o [output assembly file]

可以觀察一段 C code 對應的 RISC-V 組合語言為何 (比如 for 迴圈會產生怎樣的組合語言),基本上都可以套用到作業裡。

PlusoneWang commented 2 years ago

Hi TA,

About the first question, I expected it should print the value of a, b, i but it only show a line of bbl loader. The contents of test1.S are totally copied from the README.md as following.

    .file "test1.p"
    .option nopic
.comm a, 4, 4             # emit object 'a' to .bss section with size = 4, align = 4
.section    .rodata       # emit rodata section
    .align 2
    .globl d              # emit symbol 'd' to the global symbol table
    .type d, @object
d:
    .word 5
.section    .text
    .align 2
    .globl sum
    .type sum, @function
sum:
    addi sp, sp, -128
    sw ra, 124(sp)
    sw s0, 120(sp)
    addi s0, sp, 128
    sw a0, -12(s0)        # save parameter 'a' in the local stack
    sw a1, -16(s0)        # save parameter 'b' in the local stack
    addi t0, s0, -20      # load the address of 'c'
    addi sp, sp, -4
    sw t0, 0(sp)          # push the address to the stack
    lw t0, -12(s0)        # load the value of 'a'
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, -16(s0)        # load the value of 'b'
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    lw t1, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    add t0, t1, t0        # a + b, always save the value in a certain register you choose
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    lw t1, 0(sp)          # pop the address from the stack
    addi sp, sp, 4
    sw t0, 0(t1)          # save the value to 'c'
    lw t0, -20(s0)
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    mv a0, t0             # load the value of 'c' to the return value register 'a0'
    lw ra, 124(sp)
    lw s0, 120(sp)
    addi sp, sp, 128
    jr ra
    .size sum, .-sum
.section    .text
    .align 2
    .globl main           # emit symbol 'main' to the global symbol table
    .type main, @function
main:
    # in the function prologue
    addi sp, sp, -128     # move stack pointer to lower address to allocate a new stack
    sw ra, 124(sp)        # save return address of the caller function in the current stack
    sw s0, 120(sp)        # save frame pointer of the last stack in the current stack
    addi s0, sp, 128      # move frame pointer to the bottom of the current stack
    # b = 5
    addi t0, s0, -12
    addi sp, sp, -4
    sw t0, 0(sp)          # push the address to the stack
    li t0, 5
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    lw t1, 0(sp)          # pop the address from the stack
    addi sp, sp, 4
    sw t0, 0(t1)          # b = 5
    # c = 6
    addi t0, s0, -16
    addi sp, sp, -4
    sw t0, 0(sp)          # push the address to the stack
    li t0, 6
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    lw t1, 0(sp)          # pop the address from the stack
    addi sp, sp, 4
    sw t0, 0(t1)          # c = 6
    # read a
    la t0, a              # load the address of 'a'
    addi sp, sp, -4
    sw t0, 0(sp)          # push the address to the stack
    jal ra, readInt       # call function 'readInt'
    lw t0, 0(sp)          # pop the address from the stack
    addi sp, sp, 4
    sw a0, 0(t0)          # save the return value to 'a'
    # print a
    la t0, a
    lw t1, 0(t0)          # load the value of 'a'
    mv t0, t1
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw a0, 0(sp)          # pop the value from the stack to the first argument register 'a0'
    addi sp, sp, 4
    jal ra, printInt      # call function 'printInt'
    # a = sum(b, d)
    la t0, a              # load the address of 'a'
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, -12(s0)        # load the value of 'b'
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    la t0, d              # load the address of 'd'
    lw t1, 0(t0)          # load the 32-bit value of 'd'
    mv t0, t1
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw a1, 0(sp)          # pop the value from the stack to the second argument register 'a1'
    addi sp, sp, 4
    lw a0, 0(sp)          # pop the value from the stack to the first argument register 'a0'
    addi sp, sp, 4
    jal ra, sum           # call function 'sum'
    mv t0, a0             # always move the return value to a certain register you choose
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    lw t1, 0(sp)          # pop the address from the stack
    addi sp, sp, 4
    sw t0, 0(t1)          # save the value to 'a'
    la t0, a
    lw a0, 0(t0)
    jal ra, printInt
    # a = (b + c) * d
    addi sp, sp, -4
    la t0, a              # load the address of 'a'
    sw t0, 0(sp)          # push the address to the stack
    lw t0, -12(s0)        # load the value of 'b'
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, -16(s0)        # load the value of 'c'
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    lw t1, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    add t0, t1, t0        # b + c, always save the value in a certain register you choose
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    la t0, d              # load the address of 'd'
    lw t1, 0(t0)          # load the 32-bit value of 'd'
    mv t0, t1
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    lw t1, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    mul t0, t1, t0        # (b + c) * d, always save the value in a certain register you choose
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    lw t1, 0(sp)          # pop the address from the stack
    addi sp, sp, 4
    sw t0, 0(t1)          # save the value to 'a'
    la t0, a
    lw a0, 0(t0)
    jal ra, printInt
    # condition example
    la t0, a
    lw t1, 0(t0)          # load the value of 'a'
    mv t0, t1
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    li t0, 40
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    lw t1, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    bgt t1, t0, L2        # if a > 40, jump to L2
L1:
    la t0, a
    lw t1, 0(t0)          # load the value of 'a'
    mv t0, t1
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw a0, 0(sp)          # pop the value from the stack to the first argument register 'a0'
    addi sp, sp, 4
    jal ra, printInt      # call function 'printInt'
    j L3                  # jump to L3
L2:
    lw t0, -12(s0)        # load the value of 'b'
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw a0, 0(sp)          # pop the value from the stack to the first argument register 'a0'
    addi sp, sp, 4
    jal ra, printInt      # call function 'printInt'
L3:
    # while loop example
    lw t0, -12(s0)        # load the value of 'b'
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    li t0, 8
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    lw t1, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    bge t1, t0, L5        # if b >= 8, exit the loop
L4:
    lw t0, -12(s0)        # load the value of 'b'
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw a0, 0(sp)          # pop the value from the stack to the first argument register 'a0'
    addi sp, sp, 4
    jal ra, printInt      # call function 'printInt'
    addi t0, s0, -12      # load the address of 'b'
    addi sp, sp, -4
    sw t0, 0(sp)          # push the address to the stack
    lw t0, -12(s0)        # load the value of 'b'
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    li t0, 1
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    lw t1, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    add t0, t1, t0        # b + 1, always save the value in a certain register you choose
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    lw t1, 0(sp)          # pop the address from the stack
    addi sp, sp, 4
    sw t0, 0(t1)          # save the value to 'b'
    j L3                  # jump back to loop condition
L5:
    # for loop example
    addi t0, s0, -20
    addi sp, sp, -4
    sw t0, 0(sp)          # push the address of the loop variable to the stack
    li t0, 10
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    lw t1, 0(sp)          # pop the address from the stack
    addi sp, sp, 4
    sw t0, 0(t1)          # save the loop variable in the local stack
L6:
    lw t0, -20(s0)        # load the value of 'i'
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    li t0, 13
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    lw t1, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    bge t1, t0, L8        # if i >= 13, exit the loop
L7:
    lw t0, -20(s0)        # load the value of 'i'
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw a0, 0(sp)          # pop the value from the stack to the first argument register 'a0'
    addi sp, sp, 4
    jal ra, printInt      # call function 'printInt'
    addi t0, s0, -20      # load the address of 'i'
    addi sp, sp, -4
    sw t0, 0(sp)          # push the address to the stack
    lw t0, -20(s0)        # load the value of 'i'
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    li t0, 1
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    lw t1, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    add t0, t1, t0        # i + 1, always save the value in a certain register you choose
    addi sp, sp, -4
    sw t0, 0(sp)          # push the value to the stack
    lw t0, 0(sp)          # pop the value from the stack
    addi sp, sp, 4
    lw t1, 0(sp)          # pop the address from the stack
    addi sp, sp, 4
    sw t0, 0(t1)          # save the value to 'i'
    j L6                  # jump back to loop condition
L8:
    # in the function epilogue
    lw ra, 124(sp)        # load return address saved in the current stack
    lw s0, 120(sp)        # move frame pointer back to the bottom of the last stack
    addi sp, sp, 128      # move stack pointer back to the top of the last stack
    jr ra                 # jump back to the caller function
    .size main, .-main
LittleLaGi commented 2 years ago

你提供的程式應該是把作業說明的範例程式接在一起後,人工把一些變數的部分修改成 stack 的操作? 它看起來是卡在無窮迴圈裡,也有可能是不小心跳到不合法的位址,我沒有去細看是哪邊造成的, 不過如果你想測試整個編譯、執行的流程的話,可以用下面這段程式:

.section    .text
    .align 2
    .globl main           # emit symbol 'main' to the global symbol table
    .type main, @function
main:
    # in the function prologue
    addi sp, sp, -128     # move stack pointer to lower address to allocate a new stack
    sw ra, 124(sp)        # save return address of the caller function in the current stack
    sw s0, 120(sp)        # save frame pointer of the last stack in the current stack
    addi s0, sp, 128      # move frame pointer to the bottom of the current stack

    li a0, 777
    jal ra, printInt

    # in the function epilogue
    lw ra, 124(sp)        # load return address saved in the current stack
    lw s0, 120(sp)        # move frame pointer back to the bottom of the last stack
    addi sp, sp, 128      # move stack pointer back to the top of the last stack
    jr ra                 # jump back to the caller function
    .size main, .-main

不曉得這是不是你想要測試的?

ChukaChiu commented 2 years ago

Hi 同學,

如果你是找不到起始的方向, 可以參考我的作法, 如果是我誤解了請忽略這則回覆。

這次作業主要是在CodeGenerator.cpp添加一些代碼, make test後會產生對應test case的.S檔, 並執行.S檔內的指令, 期望執行後的輸出如同sample-solutions

一開始clone下來的hw5是無法產生最基本的.S內容, 所以你make test後會看到一些錯誤訊息在你的diff.txt內, 可以試著在下方代碼中補上作業說明的"An empty P program"部分, 再次make test就可以看到錯誤消失。

void CodeGenerator::visit(ProgramNode &p_program) {
    // Generate RISC-V instructions for program header
    // clang-format off
    constexpr const char*const riscv_assembly_file_prologue =
        "    .file \"%s\"\n"
        "    .option nopic\n"
        ".section    .text\n"
        "    .align 2\n";
    // clang-format on
    dumpInstructions(m_output_file.get(), riscv_assembly_file_prologue,
                     m_source_file_path.c_str());

當然實際不是這樣子寫, 但可以大約知道後續會需要在各個位置用dumpInstructions完成我們的.S內容

PlusoneWang commented 2 years ago

Hi @ChukaChiu, Thank you for your suggestion, I already did that and now unable to manage the stack/register well.

Hi @LittleLaGi, What I want to do is observe the sample code in the README as the reference to generate the instrations. I didn't modify the test1.S, please refer the Combining All Examples Above section in the README.md.

LittleLaGi commented 2 years ago

原來在那邊 XD 我自己都忘記有那部份了,抱歉! 那是因為 read a; 在等你輸入數字,輸入後剩下的都會正常執行