Системски софтвер/К1 2022 — разлика између измена

Извор: SI Wiki
Пређи на навигацију Пређи на претрагу
м (Ispravljen naziv tipa)
м (→‎3. задатак: Bez vodećih nula kao što piše u napomeni)
 
(Једна међуизмена истог корисника није приказана)
Ред 109: Ред 109:
# Наредба <syntaxhighlight lang="c" inline>printf("%p", identifierArr);</syntaxhighlight> исписује <span class="spoiler" data-solution="text">0x4050607080A0</span>.
# Наредба <syntaxhighlight lang="c" inline>printf("%p", identifierArr);</syntaxhighlight> исписује <span class="spoiler" data-solution="text">0x4050607080A0</span>.
# Наредба <syntaxhighlight lang="c" inline>printf("%p", &identifierArr);</syntaxhighlight> исписује <span class="spoiler" data-solution="text">0x4050607080A0</span>.
# Наредба <syntaxhighlight lang="c" inline>printf("%p", &identifierArr);</syntaxhighlight> исписује <span class="spoiler" data-solution="text">0x4050607080A0</span>.
# Наредба <syntaxhighlight lang="c" inline>printf("%#x", identifierArr[0]);</syntaxhighlight> исписује <span class="spoiler" data-solution="text">0x88887777</span>.
# Наредба <syntaxhighlight lang="c" inline>printf("%#x", identifierArr[0]);</syntaxhighlight> исписује <span class="spoiler" data-solution="text">0x6070809C</span>.
# Наредба <syntaxhighlight lang="c" inline>printf("%#x", identifierArr[1]);</syntaxhighlight> исписује <span class="spoiler" data-solution="text">0x6070809C</span>.
# Наредба <syntaxhighlight lang="c" inline>printf("%#x", identifierArr[1]);</syntaxhighlight> исписује <span class="spoiler" data-solution="text">0x4050</span>.
</div>
</div>
'''Напомене:'''
'''Напомене:'''

Тренутна верзија на датум 29. март 2023. у 15:53

Први колоквијум 2022. године на СИ одсеку одржан је 28. марта. На колоквијуму су од литературе били доступни SystemV ABI и amd64 Architecture Programmer's Manual, и било је дозвољено покренути Ubuntu виртуелну машину која се користила и на вежбама, са свим истим алатима. Првих 40 минута се радио теоријски део, наредних 50 минута задатак, док је после колоквијума био могућ увид у радове (разлог из ког није био могућ обрнут редослед рада теоријског дела и задатка је због тога што претходних година неки студенти не би чули напомену да не треба да покрену оба теста истовремено, па би имали максимално 50 минута за израду оба).

  • За питања са више одговора, тачни одговори су подебљани и уоквирени
  • За питања за које се одговори уносе, тачни одговори су подвучени и сакривени, тако да се прикажу када изаберете тај текст (пример: овако)
  • Притисните лево дугме испод за сакривање и откривање свих одговора, или десно дугме за укључивање и искључивање интерактивног режима:

Теорија

1. задатак

У наставку је дат изворни асемблерски код функције foo:

.intel_syntax noprefix
.global foo
.type foo, @function
foo:
    push rsp
    mov rax, rsp
    and rax, 0x0F
    cmp rax, 0
    je equal
    mov rax, 0
    jmp return
equal:
    mov rax, 1
return:
    pop rsp
    ret
.end

Шта је тачно за повратну вредност функције foo уколико се посматра amd64 архитектура и System V ABI конвенција?

  1. Повратну вредност функције није могуће детерминистички одредити све до тренутка извршавања.
  2. Повратна вредност функције је 0 (нула) због постојања "црвене зоне".
  3. Повратна вредност функције је 0 (нула) зато што је стек подразумевано смештен у виши део адресног простора.
  4. Повратна вредност функције је 1 (један) услед гарантованог поравнања области за аргументе.
  5. Повратна вредност функције је 1 (један) јер посматрана функција не позива друге функције.

2. задатак

У наставку је дата декларација функције foo и дефиниције пратећих типова података:

typedef struct
{
    long fA1;
    long fA2;
} StructTypeA;

typedef struct
{
    long fB1;
    double fB2;
} StructTypeB;

extern StructTypeB foo(
    StructTypeA param0,
    StructTypeA param1,
    StructTypeB param2,
    StructTypeA param3,
    void * param4,
    void * param5);

Допунити следеће констатације уколико се посматра amd64 архитектура и System V ABI конвенција:

  1. Повратна вредност функције foo прослеђује се као комбинација GP/SSE назад до позиваоца.
  2. Параметар param0 прослеђује се као комбинација GP у функцију foo приликом њеног позива.
  3. Параметар param1 прослеђује се као комбинација GP у функцију foo приликом њеног позива.
  4. Параметар param2 прослеђује се као комбинација GP/SSE у функцију foo приликом њеног позива.
  5. Параметар param3 прослеђује се као stackPushII у функцију foo приликом њеног позива.
  6. Параметар param4 прослеђује се као r9 у функцију foo приликом њеног позива.
  7. Параметар param5 прослеђује се као stackPushI у функцију foo приликом њеног позива.

Напомене:

  • Одговор комбинација GP представља одређену комбинацију (више од једног) искључиво General Purpose регистара.
  • Одговор комбинација SSE представља одређену комбинацију (више од једног) искључиво Streaming SIMD Extension регистара.
  • Одговор комбинација GP/SSE представља одређену комбинацију (више од једног) General Purpose и Streaming SIMD Extension регистара.
  • Одговор stackPush<roman-numeral>, где је <roman-numeral> римски број, представља аргумент који се прослеђује преко стека при чему римски број означава међусобни поредак push операција односно редослед стављања датог аргумента на врх стека у односу на друге аргументе који се такође прослеђују преко стека.

3. задатак

Посматра се програм описан садржајем дела меморије и сегментом изворног C кода. Иницијални садржај дела меморије (дат у "школском" формату приказаном на аудиторним вежбама):

   +7     +6     +5     +4     +3     +2     +1     +0
| 0x00 | 0x00 | 0xFF | 0xFF | 0xEE | 0xEE | 0xDD | 0xDD | <--- 0x405060708090 + 0x20
| 0xCC | 0xCC | 0xBB | 0xBB | 0xAA | 0xAA | 0x99 | 0x99 | <--- 0x405060708090 + 0x18
| 0x00 | 0x00 | 0x40 | 0x50 | 0x60 | 0x70 | 0x80 | 0x9C | <--- 0x405060708090 + 0x10
| 0x88 | 0x88 | 0x77 | 0x77 | 0x66 | 0x66 | 0x55 | 0x55 | <--- 0x405060708090 + 0x08
| 0x44 | 0x44 | 0x33 | 0x33 | 0x22 | 0x22 | 0x11 | 0x11 | <--- 0x405060708090 + 0x00

Сегмент изворног C кода:

#include <stdio.h>
#include <stdint.h>

extern uint32_t *identifierPtr;
extern uint32_t identifierArr[];

void main()
{
    printf("%p", identifierPtr);
    printf("%p", &identifierPtr);
    printf("%#x", identifierPtr[0]);
    printf("%#x", identifierPtr[1]);
    printf("%p", identifierArr);
    printf("%p", &identifierArr);
    printf("%#x", identifierArr[0]);
    printf("%#x", identifierArr[1]);
}

Допунити следеће констатације уколико се посматра amd64 архитектура и System V ABI конвенција, а симболи identifierPtr и identifierArr имају исту вредност 0x4050607080A0:[1]

  1. Наредба printf("%p", identifierPtr); исписује 0x40506070809C.
  2. Наредба printf("%p", &identifierPtr); исписује 0x4050607080A0.
  3. Наредба printf("%#x", identifierPtr[0]); исписује 0x88887777.
  4. Наредба printf("%#x", identifierPtr[1]); исписује 0x6070809C.
  5. Наредба printf("%p", identifierArr); исписује 0x4050607080A0.
  6. Наредба printf("%p", &identifierArr); исписује 0x4050607080A0.
  7. Наредба printf("%#x", identifierArr[0]); исписује 0x6070809C.
  8. Наредба printf("%#x", identifierArr[1]); исписује 0x4050.

Напомене:

  • Уколико неку вредност није могуће одредити на основу датог садржаја дела меморије као одговор треба унети знак питања (?)
  • Све одговоре за успешно одређене вредности треба унети у истом формату каквом их програм исписује.
  • Формат "%p" служи за испис вредности показивача у хексадецималном формату са префиксом 0x (након префикса не исписују се водеће нуле).
  • Формат "%#x" служи за испис неозначеног целог броја у хексадецималном формату са префиксом 0x (након префикса не исписују се водеће нуле).

4. задатак

У наставку је дата дефиниција неког типа података StructType:

typedef struct
{
    char f1;
    int f2;
    short f3;
    float f4;
    char f5;
} StructType;

Означити у наставку шта представља сваки бајт дела меморије (дат у "школском" формату приказаном на аудиторним вежбама) под следећим претпоставкама:

  • структура StructType смештена је на прво одговарајуће слободно место у датом делу меморије,
  • слободан простор у датом делу меморије почиње на адреси 0x8000004502 и
  • посматра се amd64 архитектура и System V ABI конвенција.
+7 +6 +5 +4 +3 +2 +1 +0
out out out out out out out out <--- 0x8000004500 + 0x18
padd padd padd f5 f4 f4 f4 f4 <--- 0x8000004500 + 0x10
padd padd f3 f3 f2 f2 f2 f2 <--- 0x8000004500 + 0x08
padd padd padd f1 out out out out <--- 0x8000004500 + 0x00

Напомене:

  • Одговор out представља бајт изван посматране структуре.
  • Одговор padd представља неискоришћени односно padding бајт унутар посматране структуре.

5. задатак

У наставку је дат садржај датотеке main.c са изворним C кодом:

#include <stdio.h>

int main()
{
    printf("Hello World!\n");
    return 0;
}

Посматра се amd64 архитектура и System V ABI конвенција, а покренуте су следеће команде:

gcc -S -o main.s main.c
as -o main.o main.s
ld -o executable \
    --entry=_start \
    /lib/x86_64-linux-gnu/crt1.o \
    /lib/x86_64-linux-gnu/crti.o \
    /lib/x86_64-linux-gnu/crtn.o \
    -lc \
    main.o
./executable
  1. Програм се регуларно извршава и исписује поруку Hello World! на стандардни излаз.
  2. Није могуће добити извршну датотеку executable зато што симбол који представља улазну тачку није дефинисан.
  3. Није могуће добити извршну датотеку executable зато што у процес линковања није укључена стандардна C библиотека.
  4. Извршавање програма се зауставља приликом пуњења у оперативну меморију зато што није познато ко учитава динамичке библиотеке.
  5. Није могуће добити извршну датотеку executable зато што у процес линковања нису укључене C runtime објектне датотеке.

Задатак

Поставка

У наставку је дат сегмент изворног асемблерског кода написан за amd64 архитектуру према System V ABI конвенцији:

.intel_syntax noprefix
.text
.global foo
.type foo, @function
foo:
    endbr64
    mov rcx, QWORD PTR 24[rsp]
    movsx rdx, si
    movsx esi, si
    mov rax, rdi
    imul esi, DWORD PTR 16[rsp]
    imul rcx, rdx
    imul rdx, QWORD PTR 8[rsp]
    mov DWORD PTR 8[rdi], esi
    mov QWORD PTR 16[rdi], rcx
    mov QWORD PTR [rdi], rdx
    ret

Написати сегмент изворног C кода, који одговара наведеном сегменту изворног асемблерског кода, тако да садржи само следеће елементе:

  • дефиниције потенцијално потребних типова података и
  • дефиницију функције foo.

Напомене:

  • Уколико се текстуални едитор Ace не учита на исправан начин треба освежити интернет страницу односно извршити refresh (претходно унети одговори на друга питања чувају се на серверу и неће бити изгубљени услед освежавања интернет странице).
  • Кликом на дугме за проверу решења могуће је одмах, чак и пре предаје, испитати исправност решења. Penalty regime дефинише износ казне односно пенала за сваку проверу решења изражено у процентима максималног могућег броја поена за ово питање. У складу са вредношћу Penalty regime пенали за проверу решења редом износе 0%, 0%, 0%, 30%, 40%, 50% и 60%. Дакле, само прве три провере решења не узрокују никакав пенал, четврта провера решења узрокује пенал од 30%, пета пенал од 40%, шеста пенал од 50%, док свака провера решења почев од седме узрокује пенал од 60% (потпуно тачно решење које је проверавано седам или више пута биће оцењено са (100 - 60)% поена).

Напомене

Следеће напомене су биле поменуте током колоквијума:

  • Оригинални C програм је компајлиран користећи GCC опцију -O3 за оптимизацију.
  • Постојала су четири тест примера од 10, 30, 30 и 30 бодова.
  • Moodle оцењивач није користио опцију за оптимизацију, и очекивао је од студената да не алоцирају објекте на стеку. Због овога, може да се деси да студенти добију идентичан испис objdump над објектним фајлом свог компајлираног кода као што је асемблерски код дат у задатку али да последња два тест примера не прођу.
  • Начин кастовања структуре је објашњен на колоквијуму.

Решење

typedef struct {
    long a;
    int b;
    long c;
} StructType;

StructType foo(short arg, StructType p) {
    return (StructType) {
        p.a * arg,
        p.b * arg,
        p.c * arg
    };
}

Напомене

  1. На колоквијуму је на овом месту слово А писало ћирилицом, па се студентима који су копирали адресу одавде нису признали бодови на местима где се та вредност тражила. Током увида, асистент је приметио грешку и рекао да ће исправити бодове.