2014-09-29 4 views
3

Как именно я конвертирую эту программу C в код сборки? Мне сложно понять этот процесс или как начать его. Я новичок в этом. Любая помощь будет оценена!Преобразование программы C в код сборки

while(a!=b){ 
    if(a > b){ 
     a = a - b; 
     } 
     else{ 
      b = b - a; 
    } 
    } 
    return a; 
    } 

Боковое примечание: предположим, что в регистре R0 и R1 уже указаны два натуральных числа a и b.
Можете ли вы оставить комментарии, объясняя, как вы это сделали?

+8

Используйте параметр компилятора C для создания кода сборки. –

+0

Прочтите следующие ответы: http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem –

+0

Держу пари, что курс, который вы принимаете, использует сборку MIPS. Вы не найдете много профессионалов, знакомых с MIPS. Просто изучите это. – OregonTrail

ответ

9

Если вы используете gcc, вы можете получить сборку как gcc -S -o a.s a.c, если ваш исходный код a.c. Если вы используете Visual Studio, вы можете получить его при отладке, выбрав окно «дизассемблирование». Вот выход из Visual Studio (я назвал subrountine/функция называется «общим», поэтому «общий» появляется):

while(a!=b){ 
    003613DE mov   eax,dword ptr [a] 
    003613E1 cmp   eax,dword ptr [b] 
    003613E4 je   common+44h (0361404h) 
     if(a > b){ 
    003613E6 mov   eax,dword ptr [a] 
    003613E9 cmp   eax,dword ptr [b] 
    003613EC jle   common+39h (03613F9h) 
      a = a - b; 
    003613EE mov   eax,dword ptr [a] 
    003613F1 sub   eax,dword ptr [b] 
    003613F4 mov   dword ptr [a],eax 
     } 
     else{ 
    003613F7 jmp   common+42h (0361402h) 
      b = b - a; 
    003613F9 mov   eax,dword ptr [b] 
    003613FC sub   eax,dword ptr [a] 
    003613FF mov   dword ptr [b],eax 
     } 
     } 
    00361402 jmp   common+1Eh (03613DEh) 
     return a; 
    00361404 mov   eax,dword ptr [a] 
    } 

Здесь переменная a сохраняется в памяти изначально и так b (dword ptr [b]).

8

Профессор, который научил меня системному программированию, использовал то, что он назвал «атомарно-С» в качестве ступеньки между С и сборкой. Правила для атомно-C являются (насколько я помню):

  1. только простые выражения допускаются, т.е. a = b + c; допускается a = b + c + d; не допускается, потому что есть два оператора там.
  2. Разрешены только простые булевы выражения в инструкции if, то есть if (a < b) разрешен, но if ((a < b) && (c < d)) не разрешен.
  3. только в том случае, если утверждения, нет блоков.
  4. не для/время или делать-то время разрешено, только Гото и лейбла

Итак, выше программа будет переводить в;

label1: 
    if (a == b) 
     goto label2; 

    if (a < b) 
     goto label4; 

    a = a - b; 
    goto label3; 

label4: 
    b = b - a; 

label3: 
    goto label1; 

label2: 
    return a; 

Надеюсь, я понял это правильно ... Прошло почти двадцать лет с тех пор, как я в последний раз должен был написать атом-С. Теперь, полагая, что это правильно, давайте начнем преобразовывать некоторые из операторов атома-С в MIPS (при условии, что это то, что вы используете). По этой ссылке, предоставленной Elliott Фриша, мы можем почти сразу перевести шаги вычитания:

a = a - b  becomes R0 = R0 - R1 which is: SUBU R0, R0, R1 
b = b - a  becomes R1 = R1 - R0 which is: SUBU R1, R1, R0 

Я без знака вычитания из-за одновременно и б быть положительными целыми числами.

Сравнения можно сделать таким образом:

if(a == b) goto label2 becomes if(R0 == R1) goto label2 which is: beq R0, R1, L2? 

Проблема здесь состоит в том, что третий параметр Beq оп-кода является смещение, что движется ПК. Мы не будем знать эту ценность до тех пор, пока мы не выполним сборку рук здесь.

Неравенство - это больше работы. Если мы оставим инструкции псевдокода, нам сначала нужно будет использовать op-код set on less than, который помещает один в регистр назначения, если первый регистр меньше второго. Как только мы это сделаем, мы можем использовать branch on equal, как описано выше.

if(a < b)    becomes slt R2, R0, R1 
    goto label4     beq R2, 1, L4?   

Скачки просты, они просто j, а затем ярлык для перехода на. Таким образом,

goto label1 becomes j label1 

Последнее, что нам нужно для обработки - это возврат. Возврат осуществляется путем перемещения значения, которое мы хотим присвоить специальному регистру V0, а затем перейти к следующей команде после вызова этой функции. Проблема заключается в том, что MIPS не имеет регистра для регистрации команды перемещения (или, если она ее забыла), поэтому мы переходим из регистра в оперативную память, а затем обратно. Наконец, мы используем специальный регистр R31, который содержит обратный адрес.

return a  becomes var = a  which is SW R0, var 
         ret = var which is LW var, V0 
         jump RA  which is JR R31 

С этой информацией программа становится. И мы можем также регулировать скачки, которые мы не знали раньше:

  L1: 
0x0100  BEQ R0, R1, 8 
0x0104  SLT R2, R0, R1     ; temp = (a < b) temp = 1 if true, 0 otherwise 
0x0108  LUI R3, 0x01     ; load immediate 1 into register R3 
0x010C  BEQ R2, 1, 2     ; goto label4   
0x0110  SUBU R0, R0, R1    ; a = a - b 
0x0114  J L3       ; goto label3 
      L4: 
0x0118  SUBU R1, R1, R0    ; b = b - a; 
      L3: 
0x011C  J L1       ; goto lable1 
      L2: 
0x0120  SW R0, ret      ; move return value from register to a RAM location 
0xLW ret, V0      ; move return value from RAM to the return register. 
0x0124  JR R31       ; return to caller 

Прошло почти двадцать лет, так как я должен был делать такие вещи, как это (теперь дни, если мне нужна сборка я просто что предложили другие, и пусть компилятор сделает весь тяжелый подъем). Я уверен, что я сделал несколько ошибок на этом пути и буду рад за любые исправления или предложения. Я только вошел в эту длинную дискуссию, потому что я интерпретировал вопрос ОП как письменный перевод - то, что кто-то мог делать, когда они изучали сборку.

ура.

+0

Спасибо! Я пытаюсь понять компиляторы, и расшифровка кода сборки, сгенерированного gcc или другими компиляторами, - такая боль! Кстати, эти имена имеют значение? Я знаю, что я загружаюсь в регистры, но в коде сборки, скажем, BEQ A, B, 8 действителен? –

+0

Я предполагаю, что вы имеете в виду имена регистров. Если да, то да, они имеют значение. Вы, ассемблер, должны вызывать ошибку на 'BEQ A, B, 8', если вы не определили A и B как нечто. – thurizas

+0

Итак, позвольте мне получить это право, все имена операндов в инструкции по сборке из предопределенного набора (представляющего регистры)? то есть не является задачей ассемблера отображать произвольные имена в регистры, т. е. это делается во время компиляции? –

1

Я перевел этот код на 16-битной NASM сборки:

loop: 
    cmp ax, bx 
    je .end;  if A is not equal to B, then continue executing. Else, exit the loop 
    jg greater_than; if A is greater than B... 

    sub ax, bx;  ... THEN subtract B from A... 

    jmp loop;  ... and loop back to the beginning! 

.greater_than: 
    sub bx, ax;  ... ELSE, subtract A from B... 

    jmp loop;  ... and loop back to the beginning! 

.end: 
    push ax;  return A 

я использовал ax вместо r0 и bx вместо r1

0
ORG 000H     // origin 
MOV DPTR,#LUT    // moves starting address of LUT to DPTR 
MOV P1,#00000000B   // sets P1 as output port 
MOV P0,#00000000B   // sets P0 as output port 
MAIN: MOV R6,#230D   // loads register R6 with 230D 
     SETB P3.5   // sets P3.5 as input port 
     MOV TMOD,#01100001B // Sets Timer1 as Mode2 counter & Timer0 as Mode1 timer 
     MOV TL1,#00000000B // loads TL1 with initial value 
     MOV TH1,#00000000B // loads TH1 with initial value 
     SETB TR1    // starts timer(counter) 1 
BACK: MOV TH0,#00000000B // loads initial value to TH0 
     MOV TL0,#00000000B // loads initial value to TL0 
     SETB TR0    // starts timer 0 
HERE: JNB TF0,HERE   // checks for Timer 0 roll over 
     CLR TR0    // stops Timer0 
     CLR TF0    // clears Timer Flag 0 
     DJNZ R6,BACK 
     CLR TR1    // stops Timer(counter)1 
     CLR TF0    // clears Timer Flag 0 
     CLR TF1    // clears Timer Flag 1 
     ACALL DLOOP   // Calls subroutine DLOOP for displaying the count 
     SJMP MAIN   // jumps back to the main loop 
DLOOP: MOV R5,#252D 
BACK1: MOV A,TL1   // loads the current count to the accumulator 
     MOV B,#4D   // loads register B with 4D 
     MUL AB    // Multiplies the TL1 count with 4 
     MOV B,#100D   // loads register B with 100D 
     DIV AB    // isolates first digit of the count 
     SETB P1.0   // display driver transistor Q1 ON 
     ACALL DISPLAY  // converts 1st digit to 7seg pattern 
     MOV P0,A   // puts the pattern to port 0 
     ACALL DELAY 
     ACALL DELAY 
     MOV A,B 
     MOV B,#10D 
     DIV AB    // isolates the second digit of the count 
     CLR P1.0   // display driver transistor Q1 OFF 
     SETB P1.1   // display driver transistor Q2 ON 
     ACALL DISPLAY  // converts the 2nd digit to 7seg pattern 
     MOV P0,A 
     ACALL DELAY 
     ACALL DELAY 
     MOV A,B    // moves the last digit of the count to accumulator 
     CLR P1.1   // display driver transistor Q2 OFF 
     SETB P1.2   // display driver transistor Q3 ON 
     ACALL DISPLAY  // converts 3rd digit to 7seg pattern 
     MOV P0,A   // puts the pattern to port 0 
     ACALL DELAY   // calls 1ms delay 
     ACALL DELAY 
     CLR P1.2 
     DJNZ R5,BACK1  // repeats the subroutine DLOOP 100 times 
     MOV P0,#11111111B 
     RET 

DELAY: MOV R7,#250D  // 1ms delay 
DEL1: DJNZ R7,DEL1 
     RET 

DISPLAY: MOVC A,@A+DPTR // gets 7seg digit drive pattern for current value in A 
     CPL A 
     RET 
LUT: DB 3FH    // LUT starts here 
    DB 06H 
    DB 5BH 
    DB 4FH 
    DB 66H 
    DB 6DH 
    DB 7DH 
    DB 07H 
    DB 7FH 
    DB 6FH 
END 
+0

конвертировать сборку в c программирование – denish

+0

необходимо правильное форматирование и добавить описание для объяснения – jjj

+0

Этот вопрос ищет * объяснение *, а не только для рабочего кода. Ваш ответ не дает понимания исследователю и может быть удален. Пожалуйста, отредактируйте, чтобы объяснить, что вызывает наблюдаемые симптомы. –

0

https://ctoassembly.com

Try выполняя свой код здесь. Просто скопируйте его в основную функцию, определите и b переменные перед вашей петлей while, и вы хорошо пойдете.

Вы можете увидеть, как код скомпилирован для сборки с достаточным количеством объяснений, а затем вы можете выполнить код сборки внутри гипотетического ЦП.

Смежные вопросы