Machine Level Programming : Procedure 1

임승섭·2023년 4월 20일
0

Computer Systems

목록 보기
3/7

프로시저 P가 프로시저 Q를 호출하고,
Q가 실행한 후에 다시 P로 리턴한다고 가정하자.

다음과 같은 하나 이상의 mechanism이 연관된다.

  • Passing control (제어권 전달)
    : To beginning of procedure code
    : Back to retuun point
    • 프로그램 카운터는 진입할 때 Q에 대한 시작 주소로 설정되고,
      리턴할 때 P에서 Q를 호출하는 instruction 다음 instruction으로 설정되어야 한다.
  • Passing data (데이터 전달)
    : Procedure arguments
    : Return value
    • P는 하나 이상의 매개변수를 Q에 제공할 수 있어야 하며,
      Q는 다시 P로 하나의 값을 리턴할 수 있어야 한다
  • Memory management (메모리 할당과 반납)
    : Allocate during procedure execution
    : Deallocate upon return
    • Q는 시작할 때 지역변수들을 위한 공간을 할당할 수도 있고,
      리턴할 때 이 저장소를 반납할 수 있다.

Machine instructions implement the mechanisms,
but the choices are determined by designers.
These choices make up the Application Binary Interface(ABI)

Memory Layout

  1. stack
  • local variables and procedure context
  • all function calls and variables in function
  • 밑으로 내려가면서 data를 쌓기 때문에 맨 밑을 top으로 본다.
  • managed "automatically" by compiler/assembly
  • permissions : writable; not executable
  • recursive할 때 못 빠져나오는 경우 -> stack overflow
  1. Heap (Dynamic Data)
  • Since space of stack is limited, we use dynamic allocation for flexible use
  • variables allocated with new or malloc
  • 위로 올라가면서 쌓는다
  • managed "dynamically" by programmer (allocate / deallocate data)
  • permissions : writable; not executable
  1. Static Data
  • static variables (including global variables)
  • declared outside of all the functions
  • managed "statically" initialized when process starts
  • permissions : writable; not executable
  1. Literals
  • large literals / constants
  • managed "statically" initialized when process starts
  • permissions : read-only; not executable
  1. Instructions
  • all program code
  • managed "statically" initialized when process starts
  • permissions : read-only; executable

Stack

  • 스택에서 Top은 가장 낮은 주소, Bottom은 가장 높은 주소를 의미한다.

  • 스택은 작은 주소 방향으로 성장하며,

  • 스택 포인터 %rsp는 스택의 최상위 원소를 가리킨다.
    %rsp = address of "top" element, the most-recently-pushed item that is not yet popped

  • 데이터는 pushq와 popq instruction을 이용해 스택에 저장되고 읽어올 수 있다.

    • pushq Src
      : degrement %rsp by 8. 감소시킨다는 건 더 늘린다는 의미
      : store value at address giben by %rsp
    • popq Dest
      : increment %rsp by 8. 증가시킨다는 건 줄인다는 의미
      : store value at Dest
      : 이렇게 줄여도, it remains in memory at old %rsp. 여전히 남아있다.
  • 특정 값으로 초기화되지 않은 데이터를 위한 공간은 스택 포인터를 감소시켜서 간단히 할당될 수 있다. 이와 유사하게 공간은 스택 포인터를 증가시켜서 반납할 수 있다.


Calling Conventions

Passing Control 제어의 이동

  • 제어를 P에서 Q로 전달하는 것은 일단 PC를 Q를 위한 코드의 시작주소로 설정하는 것과 관련된다.
  • 나중에 Q가 리턴하면 P를 다시 실행해야 하는 코드 위치의 일부 기록을 갖고 있어야 하기 때문에 instruction call Q로 프로시저 Q를 호출에서 기록한다.
  • 이 instructions은 주소 A를 스택에 push하고, PC를 Q의 시작으로 설정한다.
  • push된 주소 A는 return address라고 불리고, call instruction 바로 다음 instruction의 주소로 계산되나.
  • 여기에 대응하는 instruction ret는 주소 A를 스택에서 pop하고 PC를 A로 세팅한다.

Flow

  • Use stack to support procedure call and return
  • Procedure call : call label
    • push return address on stack
      • Return address
        : Address of the next instruction immediately
        after call instruction
    • jump to label
  • Procedure return :: ret
    • pop return address from stack
    • jump to address

ppt 그림 좀 보면서 이해해보자

Passing data 데이터 전송

  • 호출/리턴될 때 프로시저 콜은 데이터를 인자로 전달하는 것과, 다시 어떤 값을 리턴하는 것에 관련되어 있다.
  • 프로시저로부터의 데이터 전달은 레지스터를 통해서 일어난다.
  • x86에서는 최대 6개의 정수형 인자가 레지스터로 전달될 수 있다. 이 레지스터들은 전달되는 데이터 type의 길이에 따라 레지스터 이름을 이용해 정해진 순서로 이용된다.
  • 만약 함수가 6개 이상의 정수형 인자를 가질 때, 다른 인자들은 스택으로 전달된다. 인자 1~6은 적절한 레지스터에 복사되고, 인자 7~n까지는 인자 7을 stack Top에 넣는 방법으로 저장한다.
  • 매개변수들을 스택으로 전달할 때, 모든 데이터 길이는 8의 배수로 반올림된다.

Flow

  • Registers (NOT in Memory)
    • First 6 arguments
      • %rdi
      • %rsi
      • %rdx
      • %rcx
      • %r8
      • %r9
    • return value
      • %rax

Use more than 6 parameters, you have to use Memory

  • Return Values
    By convention, values returned by procedures are placed in %rax. Choice of %rax is arbitrary.
  • Caller must make sure to save the contents of %rax before calling a callee that returns a value
  • Callee places return value into %rax
    • For return values greater than 8 bytes, best to return a pointer to them
  • Upon return, caller finds the return value in %rax

Managing local data

  • Stack allocated in Frames
    : state for a single procedure instantiation

Stack Frame

  • Contents
    • return information
    • local storage
    • temporary space (추가 공간)
  • Pointer
    • Stack pointer : %rsp
    • Frame pointer : %rbp (starting point of current frame)
      (base pointer)
    • 업로드중..
    • 얘네 8 bytes 씩 증가.
  • Management
    • space allocated when enter procedure
      • "set-up" code
      • includes push by call instruction
    • dealocated when return
      • "finish" code
      • includes pop by ret instruction

Exercise

int main() {
	int i, x = 0;
    for (i = 0; i < 3; i++) 
    	x = randSum(x);
    printf("x = %d\n", x);
    return 0;
}

int randSum(int n) {
	int y = rand() % 20;
    return n + y;
}

Q. Higher/larger address is x or y?
A. x. x is first defined than when y is defined in randSum()

Q. How many total stack frames are created?
A. 8. main(), randSum() 3, rand() 3, print()

Q. What is the maximum depth(# of frames) of the Stack?
A. 3.

x86-64/Linux Stack Frame

  • Caller's Stack Frame
    : Extra arguments (if > 6 args) for this call
  • Callee Stack Frame
    • return address (pushed by call instruction)
    • old frame pointer(optinal)
    • saved register context (when reusing registers)
    • local variables (if can't be kept in registers)
    • "Argument build" area (if callee needs to call another function - parameter for function about to call, if needed)

Exercise

  • C code
long increment(long *p, long val) {
	long x = *p;
    long y = x + val;
    *p = y;
    return x;
}

long call_incr() {
	long v1 = 351;
    long v2 = increment(&v1, 100);
    return v1 + v2;
}
  • Assembly
1st arg(p) : %rdi
2nd arg(val), y : %rsi 
x, return value : %rax

increment :
	movq (%rdi), %rax	// x = *p
    addq %rax, %rsi		// val = val + x (y랑 val 혼용?)
    movq %rsi, (%rdi)	// *p = val 
    ret
    
call_incr :
	
    // setsup space for local variables.
	subq $16, %rsp
    movq $351, 8(%rsp)   // %rsp + 8에 351 저장 -> 이거 꼭 ppt 그림 보기!!!
    
    // setup parameters for call to increment
    movl $100, %rsi		 // %rsi에 100 저장
    leaq 8(%rsp), %rdi	 // v1(%rdi)에 %rsp + 8 저장. 즉, 351을 저장  -> 이것도 그림 꼭 보자. 왜 %rax에 351이 들어오는지!!
    
    //
    call increment
    addq 8(%rsp), %rax	 // %rax = v1 + v2
    
    // de-allocate space for local vars
    addq $16, %rsp

0개의 댓글